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.
- package/.github/workflows/test-node.yml +1 -2
- package/README.md +30 -1
- package/UPGRADE.md +6 -0
- package/__snapshots__/test/storage.js.snapshot.cjs +15 -0
- package/index.js +230 -105
- package/lib/bitfield.js +3 -2
- package/lib/block-encryption.js +68 -0
- package/lib/block-store.js +3 -1
- package/lib/core.js +3 -1
- package/lib/merkle-tree.js +43 -29
- package/lib/oplog.js +4 -3
- package/lib/protocol.js +9 -6
- package/lib/replicator.js +60 -15
- package/lib/streams.js +39 -0
- package/package.json +7 -5
- package/test/basic.js +12 -0
- package/test/encryption.js +123 -0
- package/test/replicate.js +76 -0
- package/test/sessions.js +11 -1
- package/test/storage.js +31 -0
- package/test/streams.js +55 -0
package/test/replicate.js
CHANGED
|
@@ -294,3 +294,79 @@ test('multiplexing multiple times over the same stream', async function (t) {
|
|
|
294
294
|
t.is(b1.length, a1.length, 'same length')
|
|
295
295
|
t.end()
|
|
296
296
|
})
|
|
297
|
+
|
|
298
|
+
test('destroying a stream and re-replicating works', async function (t) {
|
|
299
|
+
const core = await create()
|
|
300
|
+
|
|
301
|
+
while (core.length < 33) await core.append(Buffer.from('#' + core.length))
|
|
302
|
+
|
|
303
|
+
const clone = await create(core.key)
|
|
304
|
+
|
|
305
|
+
let s1 = core.replicate(true)
|
|
306
|
+
let s2 = clone.replicate(false)
|
|
307
|
+
|
|
308
|
+
s1.pipe(s2).pipe(s1)
|
|
309
|
+
|
|
310
|
+
await s2.opened
|
|
311
|
+
|
|
312
|
+
const all = []
|
|
313
|
+
for (let i = 0; i < 33; i++) {
|
|
314
|
+
all.push(clone.get(i))
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
clone.once('download', function () {
|
|
318
|
+
// simulate stream failure in the middle of bulk downloading
|
|
319
|
+
s1.destroy()
|
|
320
|
+
})
|
|
321
|
+
|
|
322
|
+
await new Promise((resolve) => s1.once('close', resolve))
|
|
323
|
+
|
|
324
|
+
// retry
|
|
325
|
+
s1 = core.replicate(true)
|
|
326
|
+
s2 = clone.replicate(false)
|
|
327
|
+
|
|
328
|
+
s1.pipe(s2).pipe(s1)
|
|
329
|
+
|
|
330
|
+
const blocks = await Promise.all(all)
|
|
331
|
+
|
|
332
|
+
t.is(blocks.length, 33, 'downloaded 33 blocks')
|
|
333
|
+
})
|
|
334
|
+
|
|
335
|
+
test('replicate discrete range', async function (t) {
|
|
336
|
+
const a = await create()
|
|
337
|
+
|
|
338
|
+
await a.append(['a', 'b', 'c', 'd', 'e'])
|
|
339
|
+
|
|
340
|
+
const b = await create(a.key)
|
|
341
|
+
|
|
342
|
+
let d = 0
|
|
343
|
+
b.on('download', () => d++)
|
|
344
|
+
|
|
345
|
+
replicate(a, b, t)
|
|
346
|
+
|
|
347
|
+
const r = b.download({ blocks: [0, 2, 3] })
|
|
348
|
+
await r.downloaded()
|
|
349
|
+
|
|
350
|
+
t.is(d, 3)
|
|
351
|
+
t.alike(await b.get(0), Buffer.from('a'))
|
|
352
|
+
t.alike(await b.get(2), Buffer.from('c'))
|
|
353
|
+
t.alike(await b.get(3), Buffer.from('d'))
|
|
354
|
+
})
|
|
355
|
+
|
|
356
|
+
test('replicate discrete empty range', async function (t) {
|
|
357
|
+
const a = await create()
|
|
358
|
+
|
|
359
|
+
await a.append(['a', 'b', 'c', 'd', 'e'])
|
|
360
|
+
|
|
361
|
+
const b = await create(a.key)
|
|
362
|
+
|
|
363
|
+
let d = 0
|
|
364
|
+
b.on('download', () => d++)
|
|
365
|
+
|
|
366
|
+
replicate(a, b, t)
|
|
367
|
+
|
|
368
|
+
const r = b.download({ blocks: [] })
|
|
369
|
+
await r.downloaded()
|
|
370
|
+
|
|
371
|
+
t.is(d, 0)
|
|
372
|
+
})
|
package/test/sessions.js
CHANGED
|
@@ -15,6 +15,7 @@ test('sessions - can create writable sessions from a read-only core', async func
|
|
|
15
15
|
t.absent(core.writable)
|
|
16
16
|
|
|
17
17
|
const session = core.session({ keyPair: { secretKey: keyPair.secretKey } })
|
|
18
|
+
await session.ready()
|
|
18
19
|
t.ok(session.writable)
|
|
19
20
|
|
|
20
21
|
try {
|
|
@@ -74,7 +75,8 @@ test('sessions - writable session with invalid keypair throws', async function (
|
|
|
74
75
|
|
|
75
76
|
try {
|
|
76
77
|
const core = new Hypercore(ram, keyPair2.publicKey) // Create a new core in read-only mode.
|
|
77
|
-
core.session({ keyPair: keyPair1 })
|
|
78
|
+
const session = core.session({ keyPair: keyPair1 })
|
|
79
|
+
await session.ready()
|
|
78
80
|
t.fail('invalid keypair did not throw')
|
|
79
81
|
} catch {
|
|
80
82
|
t.pass('invalid keypair threw')
|
|
@@ -171,3 +173,11 @@ test('sessions - close with from option', async function (t) {
|
|
|
171
173
|
t.absent(core1.closed)
|
|
172
174
|
t.alike(await core1.get(0), Buffer.from('hello world'))
|
|
173
175
|
})
|
|
176
|
+
|
|
177
|
+
test('sessions - custom valueEncoding on session', async function (t) {
|
|
178
|
+
const core1 = new Hypercore(ram)
|
|
179
|
+
const core2 = core1.session({ valueEncoding: 'utf-8' })
|
|
180
|
+
|
|
181
|
+
await core1.append(Buffer.from('hello world'))
|
|
182
|
+
t.is(await core2.get(0), 'hello world')
|
|
183
|
+
})
|
package/test/storage.js
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
const test = require('brittle')
|
|
2
|
+
const sodium = require('sodium-universal')
|
|
3
|
+
const crypto = require('hypercore-crypto')
|
|
4
|
+
const RAM = require('random-access-memory')
|
|
5
|
+
const Hypercore = require('..')
|
|
6
|
+
|
|
7
|
+
const keyPair = crypto.keyPair(Buffer.alloc(sodium.crypto_sign_SEEDBYTES, 'seed'))
|
|
8
|
+
|
|
9
|
+
const encryptionKey = Buffer.alloc(sodium.crypto_stream_KEYBYTES, 'encryption key')
|
|
10
|
+
|
|
11
|
+
test('storage layout', async function (t) {
|
|
12
|
+
const core = new Hypercore(RAM, { keyPair })
|
|
13
|
+
|
|
14
|
+
for (let i = 0; i < 10000; i++) {
|
|
15
|
+
await core.append(Buffer.from([i]))
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
t.snapshot(core.core.blocks.storage.toBuffer().toString('base64'), 'blocks')
|
|
19
|
+
t.snapshot(core.core.tree.storage.toBuffer().toString('base64'), 'tree')
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
test('encrypted storage layout', async function (t) {
|
|
23
|
+
const core = new Hypercore(RAM, { keyPair, encryptionKey })
|
|
24
|
+
|
|
25
|
+
for (let i = 0; i < 10000; i++) {
|
|
26
|
+
await core.append(Buffer.from([i]))
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
t.snapshot(core.core.blocks.storage.toBuffer().toString('base64'), 'blocks')
|
|
30
|
+
t.snapshot(core.core.tree.storage.toBuffer().toString('base64'), 'tree')
|
|
31
|
+
})
|
package/test/streams.js
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
const test = require('brittle')
|
|
2
|
+
|
|
3
|
+
const { create } = require('./helpers')
|
|
4
|
+
|
|
5
|
+
test('basic read stream', async function (t) {
|
|
6
|
+
const core = await create()
|
|
7
|
+
|
|
8
|
+
const expected = [
|
|
9
|
+
'hello',
|
|
10
|
+
'world',
|
|
11
|
+
'verden',
|
|
12
|
+
'welt'
|
|
13
|
+
]
|
|
14
|
+
|
|
15
|
+
await core.append(expected)
|
|
16
|
+
|
|
17
|
+
for await (const data of core.createReadStream()) {
|
|
18
|
+
t.alike(data.toString(), expected.shift())
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
t.is(expected.length, 0)
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
test('read stream with start / end', async function (t) {
|
|
25
|
+
const core = await create()
|
|
26
|
+
|
|
27
|
+
const datas = [
|
|
28
|
+
'hello',
|
|
29
|
+
'world',
|
|
30
|
+
'verden',
|
|
31
|
+
'welt'
|
|
32
|
+
]
|
|
33
|
+
|
|
34
|
+
await core.append(datas)
|
|
35
|
+
|
|
36
|
+
{
|
|
37
|
+
const expected = datas.slice(1)
|
|
38
|
+
|
|
39
|
+
for await (const data of core.createReadStream({ start: 1 })) {
|
|
40
|
+
t.alike(data.toString(), expected.shift())
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
t.is(expected.length, 0)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
{
|
|
47
|
+
const expected = datas.slice(2, 3)
|
|
48
|
+
|
|
49
|
+
for await (const data of core.createReadStream({ start: 2, end: 3 })) {
|
|
50
|
+
t.alike(data.toString(), expected.shift())
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
t.is(expected.length, 0)
|
|
54
|
+
}
|
|
55
|
+
})
|