hypercore 10.0.0-alpha.1 → 10.0.0-alpha.13

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.
@@ -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
package/lib/replicator.js CHANGED
@@ -1,6 +1,7 @@
1
1
  const Protocol = require('./protocol')
2
2
  const RemoteBitfield = require('./remote-bitfield')
3
3
  const RandomIterator = require('random-array-iterator')
4
+ const b4a = require('b4a')
4
5
 
5
6
  const PKG = require('../package.json')
6
7
  const USER_AGENT = PKG.name + '/' + PKG.version + '@nodejs'
@@ -25,11 +26,12 @@ class InvertedPromise {
25
26
  }
26
27
 
27
28
  class Request {
28
- constructor (index, seek) {
29
+ constructor (index, seek, nodes) {
29
30
  this.peer = null
30
31
  this.index = index
31
32
  this.seek = seek
32
33
  this.value = seek === 0
34
+ this.nodes = nodes
33
35
  this.promises = []
34
36
  }
35
37
 
@@ -119,9 +121,10 @@ class Seek {
119
121
  }
120
122
 
121
123
  class Range {
122
- constructor (start, end, linear) {
124
+ constructor (start, end, filter, linear) {
123
125
  this.start = start
124
126
  this.end = end
127
+ this.filter = filter
125
128
  this.linear = !!linear
126
129
  this.promise = null
127
130
  this.done = false
@@ -144,7 +147,7 @@ class Range {
144
147
  }
145
148
 
146
149
  for (; this._start < this.end; this._start++) {
147
- if (!bitfield.get(this._start)) return false
150
+ if (this.filter(this._start) && !bitfield.get(this._start)) return false
148
151
  }
149
152
 
150
153
  return true
@@ -278,7 +281,9 @@ class RequestPool {
278
281
 
279
282
  _updateSeek (peer, seek) {
280
283
  if (seek.request) return false
281
- seek.request = this._requestRange(peer, seek.seeker.start, seek.seeker.end, seek.seeker.bytes)
284
+ // We have to snapshot the nodes here now, due to the caching of the request...
285
+ const nodes = log2(seek.seeker.end - seek.seeker.start)
286
+ seek.request = this._requestRange(peer, seek.seeker.start, seek.seeker.end, seek.seeker.bytes, nodes)
282
287
  return seek.request !== null
283
288
  }
284
289
 
@@ -296,10 +301,13 @@ class RequestPool {
296
301
  const end = range.end === -1 ? peer.state.length : range.end
297
302
  if (end <= range._start) return false
298
303
 
299
- if (range.linear) return !!this._requestRange(peer, range._start, end, 0)
304
+ if (range.linear) return !!this._requestRange(peer, range._start, end, 0, 0, range.filter)
300
305
 
301
306
  const r = range._start + Math.floor(Math.random() * (end - range._start))
302
- return !!(this._requestRange(peer, r, end, 0) || this._requestRange(peer, range._start, r, 0))
307
+ return !!(
308
+ this._requestRange(peer, r, end, 0, 0, range.filter) ||
309
+ this._requestRange(peer, range._start, r, 0, 0, range.filter)
310
+ )
303
311
  }
304
312
 
305
313
  _updateUpgrade (peer) {
@@ -328,7 +336,7 @@ class RequestPool {
328
336
  this.pendingUpgrade = null
329
337
  }
330
338
 
331
- _requestRange (peer, start, end, seek) {
339
+ _requestRange (peer, start, end, seek, nodes, filter = tautology) {
332
340
  const remote = peer.state.bitfield
333
341
  const local = this.core.bitfield
334
342
 
@@ -336,12 +344,12 @@ class RequestPool {
336
344
  if (end === -1) end = peer.state.length
337
345
 
338
346
  for (let i = start; i < end; i++) {
339
- if (!remote.get(i) || local.get(i)) continue
347
+ if (!filter(i) || !remote.get(i) || local.get(i)) continue
340
348
  // TODO: if this was a NO_VALUE request, retry if no blocks can be found elsewhere
341
349
  if (this.requests.has(i)) continue
342
350
 
343
351
  // TODO: if seeking and i >= core.length, let that takes precendance in the upgrade req
344
- const req = new Request(i, i < this.core.tree.length ? seek : 0)
352
+ const req = new Request(i, i < this.core.tree.length ? seek : 0, nodes)
345
353
  this.requests.set(i, req)
346
354
  this.send(peer, req)
347
355
  return req
@@ -390,16 +398,28 @@ class RequestPool {
390
398
 
391
399
  if (data.block.index < this.core.tree.length || this.core.truncating > 0) {
392
400
  try {
393
- data.block.nodes = await this.core.tree.nodes(data.block.index * 2)
401
+ data.block.nodes = Math.max(req.nodes, await this.core.tree.nodes(data.block.index * 2))
394
402
  } catch (err) {
395
403
  console.error('TODO handle me:', err.stack)
396
404
  }
397
405
  }
398
406
 
407
+ if (peer.destroyed) {
408
+ req.peer = null
409
+ this.pending.push(req)
410
+ if (upgrading) {
411
+ this.upgrading.resolve()
412
+ this.upgrading = null
413
+ }
414
+ this.replicator.updateAll()
415
+ return
416
+ }
417
+
399
418
  if (fork !== this.core.tree.fork || paused(peer, this.core.tree.fork) || this.core.truncating > 0) {
400
419
  if (peer.state.inflight > 0) peer.state.inflight--
401
420
  if (req.promises.length) { // someone is eagerly waiting for this request
402
421
  req.peer = null // resend on some other peer
422
+ this.pending.push(req)
403
423
  } else { // otherwise delete the request
404
424
  this.requests.delete(req.index)
405
425
  }
@@ -594,7 +614,7 @@ class RequestPool {
594
614
  return e.createPromise()
595
615
  }
596
616
 
597
- const r = new Request(index, 0)
617
+ const r = new Request(index, 0, 0)
598
618
 
599
619
  this.requests.set(index, r)
600
620
  this.pending.push(r)
@@ -662,8 +682,18 @@ module.exports = class Replicator {
662
682
  return promise
663
683
  }
664
684
 
665
- static createRange (start, end, linear) {
666
- return new Range(start, end, linear)
685
+ static createRange (start, end, filter, linear) {
686
+ // createRange(start, end)
687
+ if (filter === undefined) {
688
+ filter = tautology
689
+
690
+ // createRange(start, end, linear)
691
+ } else if (typeof filter === 'boolean') {
692
+ linear = filter
693
+ filter = tautology
694
+ }
695
+
696
+ return new Range(start, end, filter, linear)
667
697
  }
668
698
 
669
699
  addRange (range) {
@@ -750,8 +780,8 @@ module.exports = class Replicator {
750
780
 
751
781
  onbitfield ({ start, bitfield }, peer) {
752
782
  if (bitfield.length < 1024) {
753
- const buf = Buffer.from(bitfield.buffer, bitfield.byteOffset, bitfield.byteLength)
754
- const bigger = Buffer.concat([buf, Buffer.alloc(4096 - buf.length)])
783
+ const buf = b4a.from(bitfield.buffer, bitfield.byteOffset, bitfield.byteLength)
784
+ const bigger = b4a.concat([buf, b4a.alloc(4096 - buf.length)])
755
785
  bitfield = new Uint32Array(bigger.buffer, bigger.byteOffset, 1024)
756
786
  }
757
787
  peer.state.bitfield.pages.set(start, bitfield)
@@ -810,3 +840,18 @@ function pages (core) {
810
840
  }
811
841
 
812
842
  function noop () {}
843
+
844
+ function tautology () {
845
+ return true
846
+ }
847
+
848
+ function log2 (n) {
849
+ let res = 1
850
+
851
+ while (n > 2) {
852
+ n /= 2
853
+ res++
854
+ }
855
+
856
+ return res
857
+ }
package/lib/streams.js ADDED
@@ -0,0 +1,39 @@
1
+ const { Readable } = require('streamx')
2
+
3
+ class ReadStream extends Readable {
4
+ constructor (core, opts = {}) {
5
+ super()
6
+
7
+ this.core = core
8
+ this.start = opts.start || 0
9
+ this.end = typeof opts.end === 'number' ? opts.end : -1
10
+ this.snapshot = !opts.live && opts.snapshot !== false
11
+ this.live = !!opts.live
12
+ }
13
+
14
+ _open (cb) {
15
+ this._openP().then(cb, cb)
16
+ }
17
+
18
+ _read (cb) {
19
+ this._readP().then(cb, cb)
20
+ }
21
+
22
+ async _openP () {
23
+ if (this.end === -1) await this.core.update()
24
+ else await this.core.ready()
25
+ if (this.snapshot && this.end === -1) this.end = this.core.length
26
+ }
27
+
28
+ async _readP () {
29
+ const end = this.live ? -1 : (this.end === -1 ? this.core.length : this.end)
30
+ if (end >= 0 && this.start >= end) {
31
+ this.push(null)
32
+ return
33
+ }
34
+
35
+ this.push(await this.core.get(this.start++))
36
+ }
37
+ }
38
+
39
+ exports.ReadStream = ReadStream
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hypercore",
3
- "version": "10.0.0-alpha.1",
3
+ "version": "10.0.0-alpha.13",
4
4
  "description": "Hypercore 10",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -29,17 +29,19 @@
29
29
  "homepage": "https://github.com/hypercore-protocol/hypercore#readme",
30
30
  "dependencies": {
31
31
  "@hyperswarm/secret-stream": "^5.0.0",
32
+ "b4a": "^1.1.0",
32
33
  "big-sparse-array": "^1.0.2",
33
34
  "codecs": "^2.2.0",
34
- "compact-encoding": "^2.0.0",
35
+ "compact-encoding": "^2.5.0",
35
36
  "crc32-universal": "^1.0.1",
36
- "flat-tree": "^1.7.0",
37
- "hypercore-crypto": "^2.1.1",
37
+ "flat-tree": "^1.9.0",
38
+ "hypercore-crypto": "^3.1.0",
38
39
  "is-options": "^1.0.1",
39
40
  "random-access-file": "^2.1.4",
40
41
  "random-array-iterator": "^1.0.0",
41
42
  "safety-catch": "^1.0.1",
42
- "uint64le": "^1.0.0"
43
+ "sodium-universal": "^3.0.4",
44
+ "xache": "^1.0.0"
43
45
  },
44
46
  "devDependencies": {
45
47
  "brittle": "^1.4.1",
package/test/basic.js CHANGED
@@ -76,3 +76,15 @@ test('storage options', async function (t) {
76
76
  t.alike(await core.get(0), Buffer.from('hello'))
77
77
  t.end()
78
78
  })
79
+
80
+ test(
81
+ 'allow publicKeys with different byteLength that 32, if opts.crypto were passed',
82
+ function (t) {
83
+ const key = Buffer.alloc(33).fill('a')
84
+
85
+ const core = new Hypercore(ram, key, { crypto: {} })
86
+
87
+ t.is(core.key, key)
88
+ t.pass('creating a core with more than 32 byteLength key did not throw')
89
+ }
90
+ )
@@ -0,0 +1,123 @@
1
+ const test = require('brittle')
2
+ const RAM = require('random-access-memory')
3
+ const Hypercore = require('..')
4
+ const { create, replicate } = require('./helpers')
5
+
6
+ const encryptionKey = Buffer.alloc(32, 'hello world')
7
+
8
+ test('encrypted append and get', async function (t) {
9
+ const a = await create({ encryptionKey })
10
+
11
+ t.alike(a.encryptionKey, encryptionKey)
12
+
13
+ await a.append(['hello'])
14
+
15
+ t.is(a.byteLength, 5)
16
+ t.is(a.core.tree.byteLength, 5 + a.padding)
17
+
18
+ const unencrypted = await a.get(0)
19
+ t.alike(unencrypted, Buffer.from('hello'))
20
+
21
+ const encrypted = await a.core.blocks.get(0)
22
+ t.absent(encrypted.includes('hello'))
23
+ })
24
+
25
+ test('encrypted seek', async function (t) {
26
+ const a = await create({ encryptionKey })
27
+
28
+ await a.append(['hello', 'world', '!'])
29
+
30
+ t.alike(await a.seek(0), [0, 0])
31
+ t.alike(await a.seek(4), [0, 4])
32
+ t.alike(await a.seek(5), [1, 0])
33
+ t.alike(await a.seek(6), [1, 1])
34
+ t.alike(await a.seek(6), [1, 1])
35
+ t.alike(await a.seek(9), [1, 4])
36
+ t.alike(await a.seek(10), [2, 0])
37
+ t.alike(await a.seek(11), [3, 0])
38
+ })
39
+
40
+ test('encrypted replication', async function (t) {
41
+ const a = await create({ encryptionKey })
42
+
43
+ await a.append(['a', 'b', 'c', 'd', 'e'])
44
+
45
+ t.test('with encryption key', async function (t) {
46
+ const b = await create(a.key, { encryptionKey })
47
+
48
+ replicate(a, b, t)
49
+
50
+ await t.test('through direct download', async function (t) {
51
+ const r = b.download({ start: 0, end: a.length })
52
+ await r.downloaded()
53
+
54
+ for (let i = 0; i < 5; i++) {
55
+ t.alike(await b.get(i), await a.get(i))
56
+ }
57
+ })
58
+
59
+ await t.test('through indirect download', async function (t) {
60
+ await a.append(['f', 'g', 'h', 'i', 'j'])
61
+
62
+ for (let i = 5; i < 10; i++) {
63
+ t.alike(await b.get(i), await a.get(i))
64
+ }
65
+ })
66
+ })
67
+
68
+ t.test('without encryption key', async function (t) {
69
+ const b = await create(a.key)
70
+
71
+ replicate(a, b, t)
72
+
73
+ await t.test('through direct download', async function (t) {
74
+ const r = b.download({ start: 0, end: a.length })
75
+ await r.downloaded()
76
+
77
+ for (let i = 0; i < 5; i++) {
78
+ t.alike(await b.get(i), await a.core.blocks.get(i))
79
+ }
80
+ })
81
+
82
+ await t.test('through indirect download', async function (t) {
83
+ await a.append(['f', 'g', 'h', 'i', 'j'])
84
+
85
+ for (let i = 5; i < 10; i++) {
86
+ t.alike(await b.get(i), await a.core.blocks.get(i))
87
+ }
88
+ })
89
+ })
90
+ })
91
+
92
+ test('encrypted session', async function (t) {
93
+ const a = await create({ encryptionKey })
94
+
95
+ await a.append(['hello'])
96
+
97
+ const s = a.session()
98
+
99
+ t.alike(a.encryptionKey, s.encryptionKey)
100
+ t.alike(await s.get(0), Buffer.from('hello'))
101
+
102
+ await s.append(['world'])
103
+
104
+ const unencrypted = await s.get(1)
105
+ t.alike(unencrypted, Buffer.from('world'))
106
+ t.alike(await a.get(1), unencrypted)
107
+
108
+ const encrypted = await s.core.blocks.get(1)
109
+ t.absent(encrypted.includes('world'))
110
+ t.alike(await a.core.blocks.get(1), encrypted)
111
+ })
112
+
113
+ test('encrypted session before ready core', async function (t) {
114
+ const a = new Hypercore(RAM, { encryptionKey })
115
+ const s = a.session()
116
+
117
+ await a.ready()
118
+
119
+ t.alike(a.encryptionKey, s.encryptionKey)
120
+
121
+ await a.append(['hello'])
122
+ t.alike(await s.get(0), Buffer.from('hello'))
123
+ })