hypercore 10.0.0-alpha.0 → 10.0.0-alpha.12
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/__snapshots__/test/storage.js.snapshot.cjs +15 -0
- package/index.js +143 -36
- package/lib/bitfield.js +3 -2
- package/lib/block-encryption.js +68 -0
- package/lib/block-store.js +3 -1
- package/lib/core.js +4 -13
- 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 +21 -10
- package/test/encryption.js +123 -0
- package/test/extension.js +8 -8
- package/test/helpers/index.js +7 -3
- package/test/replicate.js +88 -12
- package/test/storage.js +31 -0
- package/test/streams.js +55 -0
package/test/replicate.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
const test = require('brittle')
|
|
2
2
|
const NoiseSecretStream = require('@hyperswarm/secret-stream')
|
|
3
|
-
const { create, replicate } = require('./helpers')
|
|
3
|
+
const { create, replicate, eventFlush } = require('./helpers')
|
|
4
4
|
|
|
5
5
|
test('basic replication', async function (t) {
|
|
6
6
|
const a = await create()
|
|
@@ -12,7 +12,7 @@ test('basic replication', async function (t) {
|
|
|
12
12
|
let d = 0
|
|
13
13
|
b.on('download', () => d++)
|
|
14
14
|
|
|
15
|
-
replicate(a, b)
|
|
15
|
+
replicate(a, b, t)
|
|
16
16
|
|
|
17
17
|
const r = b.download({ start: 0, end: a.length })
|
|
18
18
|
|
|
@@ -32,7 +32,7 @@ test('basic replication from fork', async function (t) {
|
|
|
32
32
|
|
|
33
33
|
const b = await create(a.key)
|
|
34
34
|
|
|
35
|
-
replicate(a, b)
|
|
35
|
+
replicate(a, b, t)
|
|
36
36
|
|
|
37
37
|
let d = 0
|
|
38
38
|
b.on('download', () => d++)
|
|
@@ -49,7 +49,7 @@ test('eager replication from bigger fork', async function (t) {
|
|
|
49
49
|
const a = await create()
|
|
50
50
|
const b = await create(a.key)
|
|
51
51
|
|
|
52
|
-
replicate(a, b)
|
|
52
|
+
replicate(a, b, t)
|
|
53
53
|
|
|
54
54
|
await a.append(['a', 'b', 'c', 'd', 'e', 'g', 'h', 'i', 'j', 'k'])
|
|
55
55
|
await a.truncate(4)
|
|
@@ -74,7 +74,7 @@ test('eager replication of updates per default', async function (t) {
|
|
|
74
74
|
const a = await create()
|
|
75
75
|
const b = await create(a.key)
|
|
76
76
|
|
|
77
|
-
replicate(a, b)
|
|
77
|
+
replicate(a, b, t)
|
|
78
78
|
|
|
79
79
|
const appended = new Promise(resolve => {
|
|
80
80
|
b.on('append', function () {
|
|
@@ -91,7 +91,7 @@ test('bigger download range', async function (t) {
|
|
|
91
91
|
const a = await create()
|
|
92
92
|
const b = await create(a.key)
|
|
93
93
|
|
|
94
|
-
replicate(a, b)
|
|
94
|
+
replicate(a, b, t)
|
|
95
95
|
|
|
96
96
|
for (let i = 0; i < 20; i++) await a.append('data')
|
|
97
97
|
|
|
@@ -114,7 +114,7 @@ test('high latency reorg', async function (t) {
|
|
|
114
114
|
const a = await create()
|
|
115
115
|
const b = await create(a.key)
|
|
116
116
|
|
|
117
|
-
const s = replicate(a, b)
|
|
117
|
+
const s = replicate(a, b, t)
|
|
118
118
|
|
|
119
119
|
for (let i = 0; i < 50; i++) await a.append('data')
|
|
120
120
|
|
|
@@ -130,7 +130,7 @@ test('high latency reorg', async function (t) {
|
|
|
130
130
|
|
|
131
131
|
for (let i = 0; i < 50; i++) await a.append('fork')
|
|
132
132
|
|
|
133
|
-
replicate(a, b)
|
|
133
|
+
replicate(a, b, t)
|
|
134
134
|
|
|
135
135
|
{
|
|
136
136
|
const r = b.download({ start: 0, end: a.length })
|
|
@@ -160,7 +160,7 @@ test('invalid signature fails', async function (t) {
|
|
|
160
160
|
|
|
161
161
|
await a.append(['a', 'b', 'c', 'd', 'e'])
|
|
162
162
|
|
|
163
|
-
const [s1, s2] = replicate(a, b)
|
|
163
|
+
const [s1, s2] = replicate(a, b, t)
|
|
164
164
|
|
|
165
165
|
s1.on('error', (err) => {
|
|
166
166
|
t.ok(err, 'stream closed')
|
|
@@ -186,7 +186,7 @@ test('update with zero length', async function (t) {
|
|
|
186
186
|
const a = await create()
|
|
187
187
|
const b = await create(a.key)
|
|
188
188
|
|
|
189
|
-
replicate(a, b)
|
|
189
|
+
replicate(a, b, t)
|
|
190
190
|
|
|
191
191
|
await b.update() // should not hang
|
|
192
192
|
t.is(b.length, 0)
|
|
@@ -227,7 +227,7 @@ test('async multiplexing', async function (t) {
|
|
|
227
227
|
|
|
228
228
|
// b2 doesn't replicate immediately.
|
|
229
229
|
a2.replicate(a)
|
|
230
|
-
await
|
|
230
|
+
await eventFlush()
|
|
231
231
|
b2.replicate(b)
|
|
232
232
|
|
|
233
233
|
await new Promise(resolve => b2.once('peer-add', resolve))
|
|
@@ -263,7 +263,7 @@ test('seeking while replicating', async function (t) {
|
|
|
263
263
|
const a = await create()
|
|
264
264
|
const b = await create(a.key)
|
|
265
265
|
|
|
266
|
-
replicate(a, b)
|
|
266
|
+
replicate(a, b, t)
|
|
267
267
|
|
|
268
268
|
await a.append(['hello', 'this', 'is', 'test', 'data'])
|
|
269
269
|
|
|
@@ -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/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
|
+
})
|