hypercore 10.0.0-alpha.7 → 10.0.0
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 +83 -22
- package/index.js +587 -217
- package/lib/bitfield.js +109 -41
- package/lib/block-encryption.js +3 -2
- package/lib/block-store.js +6 -4
- package/lib/caps.js +32 -0
- package/lib/core.js +166 -35
- package/lib/errors.js +50 -0
- package/lib/info.js +23 -0
- package/lib/merkle-tree.js +181 -105
- package/lib/messages.js +249 -168
- package/lib/oplog.js +4 -3
- package/lib/remote-bitfield.js +28 -7
- package/lib/replicator.js +1415 -624
- package/lib/streams.js +56 -0
- package/package.json +20 -15
- package/.github/workflows/test-node.yml +0 -23
- package/CHANGELOG.md +0 -37
- package/UPGRADE.md +0 -9
- package/examples/announce.js +0 -19
- package/examples/basic.js +0 -10
- package/examples/http.js +0 -123
- package/examples/lookup.js +0 -20
- package/lib/extensions.js +0 -76
- package/lib/protocol.js +0 -524
- package/lib/random-iterator.js +0 -46
- package/test/basic.js +0 -90
- package/test/bitfield.js +0 -71
- package/test/core.js +0 -290
- package/test/encodings.js +0 -18
- package/test/encryption.js +0 -85
- package/test/extension.js +0 -71
- package/test/helpers/index.js +0 -23
- package/test/merkle-tree.js +0 -518
- package/test/mutex.js +0 -137
- package/test/oplog.js +0 -399
- package/test/preload.js +0 -72
- package/test/replicate.js +0 -372
- package/test/sessions.js +0 -173
- package/test/user-data.js +0 -47
package/test/merkle-tree.js
DELETED
|
@@ -1,518 +0,0 @@
|
|
|
1
|
-
const test = require('brittle')
|
|
2
|
-
const Tree = require('../lib/merkle-tree')
|
|
3
|
-
const ram = require('random-access-memory')
|
|
4
|
-
|
|
5
|
-
test('nodes', async function (t) {
|
|
6
|
-
const tree = await create()
|
|
7
|
-
|
|
8
|
-
const b = tree.batch()
|
|
9
|
-
|
|
10
|
-
for (let i = 0; i < 8; i++) {
|
|
11
|
-
b.append(Buffer.from([i]))
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
b.commit()
|
|
15
|
-
|
|
16
|
-
t.is(await tree.nodes(0), 0)
|
|
17
|
-
t.end()
|
|
18
|
-
})
|
|
19
|
-
|
|
20
|
-
test('proof only block', async function (t) {
|
|
21
|
-
const tree = await create(10)
|
|
22
|
-
|
|
23
|
-
const proof = await tree.proof({
|
|
24
|
-
block: { index: 4, nodes: 2, value: true }
|
|
25
|
-
})
|
|
26
|
-
|
|
27
|
-
t.is(proof.upgrade, null)
|
|
28
|
-
t.is(proof.seek, null)
|
|
29
|
-
t.is(proof.block.index, 4)
|
|
30
|
-
t.is(proof.block.nodes.length, 2)
|
|
31
|
-
t.alike(proof.block.nodes.map(n => n.index), [10, 13])
|
|
32
|
-
|
|
33
|
-
t.end()
|
|
34
|
-
})
|
|
35
|
-
|
|
36
|
-
test('proof with upgrade', async function (t) {
|
|
37
|
-
const tree = await create(10)
|
|
38
|
-
|
|
39
|
-
const proof = await tree.proof({
|
|
40
|
-
block: { index: 4, nodes: 0, value: true },
|
|
41
|
-
upgrade: { start: 0, length: 10 }
|
|
42
|
-
})
|
|
43
|
-
|
|
44
|
-
t.is(proof.seek, null)
|
|
45
|
-
t.is(proof.block.index, 4)
|
|
46
|
-
t.is(proof.block.nodes.length, 3)
|
|
47
|
-
t.alike(proof.block.nodes.map(n => n.index), [10, 13, 3])
|
|
48
|
-
t.is(proof.upgrade.start, 0)
|
|
49
|
-
t.is(proof.upgrade.length, 10)
|
|
50
|
-
t.alike(proof.upgrade.nodes.map(n => n.index), [17])
|
|
51
|
-
t.alike(proof.upgrade.additionalNodes.map(n => n.index), [])
|
|
52
|
-
|
|
53
|
-
t.end()
|
|
54
|
-
})
|
|
55
|
-
|
|
56
|
-
test('proof with upgrade + additional', async function (t) {
|
|
57
|
-
const tree = await create(10)
|
|
58
|
-
|
|
59
|
-
const proof = await tree.proof({
|
|
60
|
-
block: { index: 4, nodes: 0, value: true },
|
|
61
|
-
upgrade: { start: 0, length: 8 }
|
|
62
|
-
})
|
|
63
|
-
|
|
64
|
-
t.is(proof.seek, null)
|
|
65
|
-
t.is(proof.block.index, 4)
|
|
66
|
-
t.is(proof.block.nodes.length, 3)
|
|
67
|
-
t.alike(proof.block.nodes.map(n => n.index), [10, 13, 3])
|
|
68
|
-
t.is(proof.upgrade.start, 0)
|
|
69
|
-
t.is(proof.upgrade.length, 8)
|
|
70
|
-
t.alike(proof.upgrade.nodes.map(n => n.index), [])
|
|
71
|
-
t.alike(proof.upgrade.additionalNodes.map(n => n.index), [17])
|
|
72
|
-
|
|
73
|
-
t.end()
|
|
74
|
-
})
|
|
75
|
-
|
|
76
|
-
test('proof with upgrade from existing state', async function (t) {
|
|
77
|
-
const tree = await create(10)
|
|
78
|
-
|
|
79
|
-
const proof = await tree.proof({
|
|
80
|
-
block: { index: 1, nodes: 0, value: true },
|
|
81
|
-
upgrade: { start: 1, length: 9 }
|
|
82
|
-
})
|
|
83
|
-
|
|
84
|
-
t.is(proof.seek, null)
|
|
85
|
-
t.is(proof.block.index, 1)
|
|
86
|
-
t.is(proof.block.nodes.length, 0)
|
|
87
|
-
t.alike(proof.block.nodes.map(n => n.index), [])
|
|
88
|
-
t.is(proof.upgrade.start, 1)
|
|
89
|
-
t.is(proof.upgrade.length, 9)
|
|
90
|
-
t.alike(proof.upgrade.nodes.map(n => n.index), [5, 11, 17])
|
|
91
|
-
t.alike(proof.upgrade.additionalNodes.map(n => n.index), [])
|
|
92
|
-
|
|
93
|
-
t.end()
|
|
94
|
-
})
|
|
95
|
-
|
|
96
|
-
test('proof with upgrade from existing state + additional', async function (t) {
|
|
97
|
-
const tree = await create(10)
|
|
98
|
-
|
|
99
|
-
const proof = await tree.proof({
|
|
100
|
-
block: { index: 1, nodes: 0, value: true },
|
|
101
|
-
upgrade: { start: 1, length: 5 }
|
|
102
|
-
})
|
|
103
|
-
|
|
104
|
-
t.is(proof.seek, null)
|
|
105
|
-
t.is(proof.block.index, 1)
|
|
106
|
-
t.is(proof.block.nodes.length, 0)
|
|
107
|
-
t.alike(proof.block.nodes.map(n => n.index), [])
|
|
108
|
-
t.is(proof.upgrade.start, 1)
|
|
109
|
-
t.is(proof.upgrade.length, 5)
|
|
110
|
-
t.alike(proof.upgrade.nodes.map(n => n.index), [5, 9])
|
|
111
|
-
t.alike(proof.upgrade.additionalNodes.map(n => n.index), [13, 17])
|
|
112
|
-
|
|
113
|
-
t.end()
|
|
114
|
-
})
|
|
115
|
-
|
|
116
|
-
test('proof block and seek, no upgrade', async function (t) {
|
|
117
|
-
const tree = await create(10)
|
|
118
|
-
|
|
119
|
-
const proof = await tree.proof({
|
|
120
|
-
seek: { bytes: 8 },
|
|
121
|
-
block: { index: 4, nodes: 2, value: true }
|
|
122
|
-
})
|
|
123
|
-
|
|
124
|
-
t.is(proof.upgrade, null)
|
|
125
|
-
t.is(proof.seek, null) // seek included in the block
|
|
126
|
-
t.is(proof.block.index, 4)
|
|
127
|
-
t.is(proof.block.nodes.length, 2)
|
|
128
|
-
t.alike(proof.block.nodes.map(n => n.index), [10, 13])
|
|
129
|
-
|
|
130
|
-
t.end()
|
|
131
|
-
})
|
|
132
|
-
|
|
133
|
-
test('proof block and seek #2, no upgrade', async function (t) {
|
|
134
|
-
const tree = await create(10)
|
|
135
|
-
|
|
136
|
-
const proof = await tree.proof({
|
|
137
|
-
seek: { bytes: 10 },
|
|
138
|
-
block: { index: 4, nodes: 2, value: true }
|
|
139
|
-
})
|
|
140
|
-
|
|
141
|
-
t.is(proof.upgrade, null)
|
|
142
|
-
t.is(proof.seek, null) // seek included in the block
|
|
143
|
-
t.is(proof.block.index, 4)
|
|
144
|
-
t.is(proof.block.nodes.length, 2)
|
|
145
|
-
t.alike(proof.block.nodes.map(n => n.index), [10, 13])
|
|
146
|
-
|
|
147
|
-
t.end()
|
|
148
|
-
})
|
|
149
|
-
|
|
150
|
-
test('proof block and seek #3, no upgrade', async function (t) {
|
|
151
|
-
const tree = await create(10)
|
|
152
|
-
|
|
153
|
-
const proof = await tree.proof({
|
|
154
|
-
seek: { bytes: 13 },
|
|
155
|
-
block: { index: 4, nodes: 2, value: true }
|
|
156
|
-
})
|
|
157
|
-
|
|
158
|
-
t.is(proof.upgrade, null)
|
|
159
|
-
t.alike(proof.seek.nodes.map(n => n.index), [12, 14])
|
|
160
|
-
t.is(proof.block.index, 4)
|
|
161
|
-
t.is(proof.block.nodes.length, 1)
|
|
162
|
-
t.alike(proof.block.nodes.map(n => n.index), [10])
|
|
163
|
-
|
|
164
|
-
t.end()
|
|
165
|
-
})
|
|
166
|
-
|
|
167
|
-
test('proof block and seek that results in tree, no upgrade', async function (t) {
|
|
168
|
-
const tree = await create(16)
|
|
169
|
-
|
|
170
|
-
const proof = await tree.proof({
|
|
171
|
-
seek: { bytes: 26 },
|
|
172
|
-
block: { index: 0, nodes: 4, value: true }
|
|
173
|
-
})
|
|
174
|
-
|
|
175
|
-
t.is(proof.upgrade, null)
|
|
176
|
-
t.alike(proof.block.nodes.map(n => n.index), [2, 5, 11])
|
|
177
|
-
t.alike(proof.seek.nodes.map(n => n.index), [19, 27])
|
|
178
|
-
|
|
179
|
-
t.end()
|
|
180
|
-
})
|
|
181
|
-
|
|
182
|
-
test('proof block and seek, with upgrade', async function (t) {
|
|
183
|
-
const tree = await create(10)
|
|
184
|
-
|
|
185
|
-
const proof = await tree.proof({
|
|
186
|
-
seek: { bytes: 13 },
|
|
187
|
-
block: { index: 4, nodes: 2, value: true },
|
|
188
|
-
upgrade: { start: 8, length: 2 }
|
|
189
|
-
})
|
|
190
|
-
|
|
191
|
-
t.alike(proof.seek.nodes.map(n => n.index), [12, 14])
|
|
192
|
-
t.is(proof.block.index, 4)
|
|
193
|
-
t.is(proof.block.nodes.length, 1)
|
|
194
|
-
t.alike(proof.block.nodes.map(n => n.index), [10])
|
|
195
|
-
t.is(proof.upgrade.start, 8)
|
|
196
|
-
t.is(proof.upgrade.length, 2)
|
|
197
|
-
t.alike(proof.upgrade.nodes.map(n => n.index), [17])
|
|
198
|
-
t.alike(proof.upgrade.additionalNodes.map(n => n.index), [])
|
|
199
|
-
|
|
200
|
-
t.end()
|
|
201
|
-
})
|
|
202
|
-
|
|
203
|
-
test('proof seek with upgrade', async function (t) {
|
|
204
|
-
const tree = await create(10)
|
|
205
|
-
|
|
206
|
-
const proof = await tree.proof({
|
|
207
|
-
seek: { bytes: 13 },
|
|
208
|
-
upgrade: { start: 0, length: 10 }
|
|
209
|
-
})
|
|
210
|
-
|
|
211
|
-
t.alike(proof.seek.nodes.map(n => n.index), [12, 14, 9, 3])
|
|
212
|
-
t.is(proof.block, null)
|
|
213
|
-
t.is(proof.upgrade.start, 0)
|
|
214
|
-
t.is(proof.upgrade.length, 10)
|
|
215
|
-
t.alike(proof.upgrade.nodes.map(n => n.index), [17])
|
|
216
|
-
t.alike(proof.upgrade.additionalNodes.map(n => n.index), [])
|
|
217
|
-
|
|
218
|
-
t.end()
|
|
219
|
-
})
|
|
220
|
-
|
|
221
|
-
test('verify proof #1', async function (t) {
|
|
222
|
-
const tree = await create(10)
|
|
223
|
-
const clone = await create()
|
|
224
|
-
|
|
225
|
-
const p = await tree.proof({
|
|
226
|
-
block: { index: 3 },
|
|
227
|
-
upgrade: { start: 0, length: 10 }
|
|
228
|
-
})
|
|
229
|
-
|
|
230
|
-
const b = await clone.verify(p)
|
|
231
|
-
b.commit()
|
|
232
|
-
|
|
233
|
-
t.is(clone.length, tree.length)
|
|
234
|
-
t.is(clone.byteLength, tree.byteLength)
|
|
235
|
-
t.is(await clone.byteOffset(6), await tree.byteOffset(6))
|
|
236
|
-
t.is(await clone.get(6), await tree.get(6))
|
|
237
|
-
|
|
238
|
-
t.end()
|
|
239
|
-
})
|
|
240
|
-
|
|
241
|
-
test('verify proof #2', async function (t) {
|
|
242
|
-
const tree = await create(10)
|
|
243
|
-
const clone = await create()
|
|
244
|
-
|
|
245
|
-
const p = await tree.proof({
|
|
246
|
-
seek: { bytes: 10 },
|
|
247
|
-
upgrade: { start: 0, length: 10 }
|
|
248
|
-
})
|
|
249
|
-
|
|
250
|
-
const b = await clone.verify(p)
|
|
251
|
-
b.commit()
|
|
252
|
-
|
|
253
|
-
t.is(clone.length, tree.length)
|
|
254
|
-
t.is(clone.byteLength, tree.byteLength)
|
|
255
|
-
t.alike(await clone.byteRange(10), await tree.byteRange(10))
|
|
256
|
-
|
|
257
|
-
t.end()
|
|
258
|
-
})
|
|
259
|
-
|
|
260
|
-
test('upgrade edgecase when no roots need upgrade', async function (t) {
|
|
261
|
-
const tree = await create(4)
|
|
262
|
-
const clone = await create()
|
|
263
|
-
|
|
264
|
-
{
|
|
265
|
-
const proof = await tree.proof({
|
|
266
|
-
upgrade: { start: 0, length: 4 }
|
|
267
|
-
})
|
|
268
|
-
|
|
269
|
-
const b = await clone.verify(proof)
|
|
270
|
-
b.commit()
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
const b = tree.batch()
|
|
274
|
-
b.append(Buffer.from('#5'))
|
|
275
|
-
b.commit()
|
|
276
|
-
|
|
277
|
-
{
|
|
278
|
-
const proof = await tree.proof({
|
|
279
|
-
upgrade: { start: 4, length: 1 }
|
|
280
|
-
})
|
|
281
|
-
|
|
282
|
-
const b = await clone.verify(proof)
|
|
283
|
-
b.commit()
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
t.is(tree.length, 5)
|
|
287
|
-
t.end()
|
|
288
|
-
})
|
|
289
|
-
|
|
290
|
-
test('lowest common ancestor - small gap', async function (t) {
|
|
291
|
-
const tree = await create(10)
|
|
292
|
-
const clone = await create(8)
|
|
293
|
-
const ancestors = await reorg(clone, tree)
|
|
294
|
-
|
|
295
|
-
t.is(ancestors, 8)
|
|
296
|
-
t.is(clone.length, tree.length)
|
|
297
|
-
t.end()
|
|
298
|
-
})
|
|
299
|
-
|
|
300
|
-
test('lowest common ancestor - bigger gap', async function (t) {
|
|
301
|
-
const tree = await create(20)
|
|
302
|
-
const clone = await create(1)
|
|
303
|
-
const ancestors = await reorg(clone, tree)
|
|
304
|
-
|
|
305
|
-
t.is(ancestors, 1)
|
|
306
|
-
t.is(clone.length, tree.length)
|
|
307
|
-
t.end()
|
|
308
|
-
})
|
|
309
|
-
|
|
310
|
-
test('lowest common ancestor - remote is shorter than local', async function (t) {
|
|
311
|
-
const tree = await create(5)
|
|
312
|
-
const clone = await create(10)
|
|
313
|
-
const ancestors = await reorg(clone, tree)
|
|
314
|
-
|
|
315
|
-
t.is(ancestors, 5)
|
|
316
|
-
t.is(clone.length, tree.length)
|
|
317
|
-
t.end()
|
|
318
|
-
})
|
|
319
|
-
|
|
320
|
-
test('lowest common ancestor - simple fork', async function (t) {
|
|
321
|
-
const tree = await create(5)
|
|
322
|
-
const clone = await create(5)
|
|
323
|
-
|
|
324
|
-
{
|
|
325
|
-
const b = tree.batch()
|
|
326
|
-
b.append(Buffer.from('fork #1'))
|
|
327
|
-
b.commit()
|
|
328
|
-
}
|
|
329
|
-
|
|
330
|
-
{
|
|
331
|
-
const b = clone.batch()
|
|
332
|
-
b.append(Buffer.from('fork #2'))
|
|
333
|
-
b.commit()
|
|
334
|
-
}
|
|
335
|
-
|
|
336
|
-
const ancestors = await reorg(clone, tree)
|
|
337
|
-
|
|
338
|
-
t.is(ancestors, 5)
|
|
339
|
-
t.is(clone.length, tree.length)
|
|
340
|
-
t.end()
|
|
341
|
-
})
|
|
342
|
-
|
|
343
|
-
test('lowest common ancestor - long fork', async function (t) {
|
|
344
|
-
const tree = await create(5)
|
|
345
|
-
const clone = await create(5)
|
|
346
|
-
|
|
347
|
-
{
|
|
348
|
-
const b = tree.batch()
|
|
349
|
-
b.append(Buffer.from('fork #1'))
|
|
350
|
-
b.commit()
|
|
351
|
-
}
|
|
352
|
-
|
|
353
|
-
{
|
|
354
|
-
const b = clone.batch()
|
|
355
|
-
b.append(Buffer.from('fork #2'))
|
|
356
|
-
b.commit()
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
{
|
|
360
|
-
const b = tree.batch()
|
|
361
|
-
for (let i = 0; i < 100; i++) b.append(Buffer.from('#' + i))
|
|
362
|
-
b.commit()
|
|
363
|
-
}
|
|
364
|
-
|
|
365
|
-
{
|
|
366
|
-
const b = clone.batch()
|
|
367
|
-
for (let i = 0; i < 100; i++) b.append(Buffer.from('#' + i))
|
|
368
|
-
b.commit()
|
|
369
|
-
}
|
|
370
|
-
|
|
371
|
-
const ancestors = await reorg(clone, tree)
|
|
372
|
-
|
|
373
|
-
t.is(ancestors, 5)
|
|
374
|
-
t.is(clone.length, tree.length)
|
|
375
|
-
|
|
376
|
-
t.ok(await audit(tree))
|
|
377
|
-
await tree.flush()
|
|
378
|
-
t.ok(await audit(tree))
|
|
379
|
-
|
|
380
|
-
t.end()
|
|
381
|
-
})
|
|
382
|
-
|
|
383
|
-
test('tree hash', async function (t) {
|
|
384
|
-
const a = await create(5)
|
|
385
|
-
const b = await create(5)
|
|
386
|
-
|
|
387
|
-
t.alike(a.hash(), b.hash())
|
|
388
|
-
|
|
389
|
-
{
|
|
390
|
-
const b = a.batch()
|
|
391
|
-
t.alike(b.hash(), a.hash())
|
|
392
|
-
b.append(Buffer.from('hi'))
|
|
393
|
-
const h = b.hash()
|
|
394
|
-
t.unlike(h, a.hash())
|
|
395
|
-
b.commit()
|
|
396
|
-
t.alike(h, a.hash())
|
|
397
|
-
}
|
|
398
|
-
|
|
399
|
-
{
|
|
400
|
-
const ba = b.batch()
|
|
401
|
-
ba.append(Buffer.from('hi'))
|
|
402
|
-
const h = ba.hash()
|
|
403
|
-
t.unlike(h, b.hash())
|
|
404
|
-
t.alike(h, a.hash())
|
|
405
|
-
ba.commit()
|
|
406
|
-
t.alike(h, b.hash())
|
|
407
|
-
}
|
|
408
|
-
|
|
409
|
-
t.end()
|
|
410
|
-
})
|
|
411
|
-
|
|
412
|
-
test('basic tree seeks', async function (t) {
|
|
413
|
-
const a = await create(5)
|
|
414
|
-
|
|
415
|
-
{
|
|
416
|
-
const b = a.batch()
|
|
417
|
-
b.append(Buffer.from('bigger'))
|
|
418
|
-
b.append(Buffer.from('block'))
|
|
419
|
-
b.append(Buffer.from('tiny'))
|
|
420
|
-
b.append(Buffer.from('s'))
|
|
421
|
-
b.append(Buffer.from('another'))
|
|
422
|
-
b.commit()
|
|
423
|
-
}
|
|
424
|
-
|
|
425
|
-
t.is(a.length, 10)
|
|
426
|
-
t.is(a.byteLength, 33)
|
|
427
|
-
|
|
428
|
-
for (let i = 0; i < a.byteLength; i++) {
|
|
429
|
-
const s = a.seek(i)
|
|
430
|
-
|
|
431
|
-
const actual = await s.update()
|
|
432
|
-
const expected = await linearSeek(a, i)
|
|
433
|
-
|
|
434
|
-
if (actual[0] !== expected[0] || actual[1] !== expected[1]) {
|
|
435
|
-
t.is(actual, expected, 'bad seek at ' + i)
|
|
436
|
-
return
|
|
437
|
-
}
|
|
438
|
-
}
|
|
439
|
-
|
|
440
|
-
t.pass('checked all byte seeks')
|
|
441
|
-
|
|
442
|
-
async function linearSeek (tree, bytes) {
|
|
443
|
-
for (let i = 0; i < tree.length * 2; i += 2) {
|
|
444
|
-
const node = await tree.get(i)
|
|
445
|
-
if (node.size > bytes) return [i / 2, bytes]
|
|
446
|
-
bytes -= node.size
|
|
447
|
-
}
|
|
448
|
-
return [tree.length, bytes]
|
|
449
|
-
}
|
|
450
|
-
})
|
|
451
|
-
|
|
452
|
-
test('clear full tree', async function (t) {
|
|
453
|
-
const a = await create(5)
|
|
454
|
-
|
|
455
|
-
t.is(a.length, 5)
|
|
456
|
-
|
|
457
|
-
await a.clear()
|
|
458
|
-
|
|
459
|
-
t.is(a.length, 0)
|
|
460
|
-
|
|
461
|
-
try {
|
|
462
|
-
await a.get(2)
|
|
463
|
-
t.fail('node should not exist now')
|
|
464
|
-
} catch {
|
|
465
|
-
t.pass('node should fail')
|
|
466
|
-
}
|
|
467
|
-
})
|
|
468
|
-
|
|
469
|
-
async function audit (tree) {
|
|
470
|
-
const flat = require('flat-tree')
|
|
471
|
-
const expectedRoots = flat.fullRoots(tree.length * 2)
|
|
472
|
-
|
|
473
|
-
for (const root of tree.roots) {
|
|
474
|
-
if (expectedRoots.shift() !== root.index) return false
|
|
475
|
-
if (!(await check(root))) return false
|
|
476
|
-
}
|
|
477
|
-
|
|
478
|
-
if (expectedRoots.length) return false
|
|
479
|
-
|
|
480
|
-
return true
|
|
481
|
-
|
|
482
|
-
async function check (node) {
|
|
483
|
-
if ((node.index & 1) === 0) return true
|
|
484
|
-
|
|
485
|
-
const [l, r] = flat.children(node.index)
|
|
486
|
-
const nl = await tree.get(l, false)
|
|
487
|
-
const nr = await tree.get(r, false)
|
|
488
|
-
|
|
489
|
-
if (!nl && !nr) return true
|
|
490
|
-
|
|
491
|
-
return tree.crypto.parent(nl, nr).equals(node.hash) && await check(nl) && await check(nr)
|
|
492
|
-
}
|
|
493
|
-
}
|
|
494
|
-
|
|
495
|
-
async function reorg (local, remote) {
|
|
496
|
-
const upgrade = { start: 0, length: remote.length }
|
|
497
|
-
const r = await local.reorg(await remote.proof({ upgrade }))
|
|
498
|
-
|
|
499
|
-
while (!r.finished) {
|
|
500
|
-
const index = r.want.end - 1
|
|
501
|
-
const nodes = r.want.nodes
|
|
502
|
-
|
|
503
|
-
await r.update(await remote.proof({ block: { index, nodes } }))
|
|
504
|
-
}
|
|
505
|
-
|
|
506
|
-
r.commit()
|
|
507
|
-
return r.ancestors
|
|
508
|
-
}
|
|
509
|
-
|
|
510
|
-
async function create (length = 0) {
|
|
511
|
-
const tree = await Tree.open(ram())
|
|
512
|
-
const b = tree.batch()
|
|
513
|
-
for (let i = 0; i < length; i++) {
|
|
514
|
-
b.append(Buffer.from('#' + i))
|
|
515
|
-
}
|
|
516
|
-
b.commit()
|
|
517
|
-
return tree
|
|
518
|
-
}
|
package/test/mutex.js
DELETED
|
@@ -1,137 +0,0 @@
|
|
|
1
|
-
const test = require('brittle')
|
|
2
|
-
const Mutex = require('../lib/mutex')
|
|
3
|
-
|
|
4
|
-
test('mutex - lock after destroy', async function (t) {
|
|
5
|
-
const mutex = new Mutex()
|
|
6
|
-
mutex.destroy()
|
|
7
|
-
try {
|
|
8
|
-
await mutex.lock()
|
|
9
|
-
t.fail('should not be able to lock after destroy')
|
|
10
|
-
} catch {
|
|
11
|
-
t.pass('lock threw after destroy')
|
|
12
|
-
}
|
|
13
|
-
})
|
|
14
|
-
|
|
15
|
-
test('mutex - graceful destroy', async function (t) {
|
|
16
|
-
t.plan(1)
|
|
17
|
-
|
|
18
|
-
const mutex = new Mutex()
|
|
19
|
-
const promises = []
|
|
20
|
-
let resolveCount = 0
|
|
21
|
-
|
|
22
|
-
for (let i = 0; i < 5; i++) {
|
|
23
|
-
promises.push(mutex.lock().then(() => resolveCount++))
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
const destroyed = mutex.destroy()
|
|
27
|
-
|
|
28
|
-
for (let i = 0; i < 5; i++) mutex.unlock()
|
|
29
|
-
|
|
30
|
-
await destroyed
|
|
31
|
-
|
|
32
|
-
t.is(resolveCount, 5)
|
|
33
|
-
})
|
|
34
|
-
|
|
35
|
-
test('mutex - quick destroy', async function (t) {
|
|
36
|
-
t.plan(2)
|
|
37
|
-
|
|
38
|
-
const mutex = new Mutex()
|
|
39
|
-
const promises = []
|
|
40
|
-
let rejectCount = 0
|
|
41
|
-
let resolveCount = 0
|
|
42
|
-
|
|
43
|
-
for (let i = 0; i < 5; i++) {
|
|
44
|
-
promises.push(mutex.lock().then(() => resolveCount++, () => rejectCount++))
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
const destroyed = mutex.destroy(new Error('Test error'))
|
|
48
|
-
|
|
49
|
-
for (let i = 0; i < 5; i++) mutex.unlock()
|
|
50
|
-
|
|
51
|
-
await destroyed
|
|
52
|
-
|
|
53
|
-
t.is(resolveCount, 1)
|
|
54
|
-
t.is(rejectCount, 4)
|
|
55
|
-
})
|
|
56
|
-
|
|
57
|
-
test('mutex - graceful then quick destroy', async function (t) {
|
|
58
|
-
t.plan(2)
|
|
59
|
-
|
|
60
|
-
const mutex = new Mutex()
|
|
61
|
-
const promises = []
|
|
62
|
-
let rejectCount = 0
|
|
63
|
-
let resolveCount = 0
|
|
64
|
-
|
|
65
|
-
for (let i = 0; i < 5; i++) {
|
|
66
|
-
promises.push(mutex.lock().then(() => resolveCount++, () => rejectCount++))
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
const destroyed = mutex.destroy()
|
|
70
|
-
mutex.destroy(new Error('Test error'))
|
|
71
|
-
|
|
72
|
-
for (let i = 0; i < 5; i++) mutex.unlock()
|
|
73
|
-
|
|
74
|
-
await destroyed
|
|
75
|
-
|
|
76
|
-
t.is(resolveCount, 1)
|
|
77
|
-
t.is(rejectCount, 4)
|
|
78
|
-
})
|
|
79
|
-
|
|
80
|
-
test('mutex - quick destroy with re-entry', async function (t) {
|
|
81
|
-
t.plan(2)
|
|
82
|
-
|
|
83
|
-
const mutex = new Mutex()
|
|
84
|
-
const promises = []
|
|
85
|
-
let rejectCount = 0
|
|
86
|
-
let resolveCount = 0
|
|
87
|
-
|
|
88
|
-
for (let i = 0; i < 5; i++) {
|
|
89
|
-
promises.push(lock())
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
const destroyed = mutex.destroy(new Error('Test error'))
|
|
93
|
-
|
|
94
|
-
for (let i = 0; i < 5; i++) mutex.unlock()
|
|
95
|
-
|
|
96
|
-
await destroyed
|
|
97
|
-
|
|
98
|
-
t.is(resolveCount, 1)
|
|
99
|
-
t.is(rejectCount, 4)
|
|
100
|
-
|
|
101
|
-
async function lock () {
|
|
102
|
-
try {
|
|
103
|
-
await mutex.lock()
|
|
104
|
-
resolveCount++
|
|
105
|
-
} catch {
|
|
106
|
-
try {
|
|
107
|
-
await mutex.lock()
|
|
108
|
-
t.fail('should never aquire it after failing')
|
|
109
|
-
} catch {
|
|
110
|
-
rejectCount++
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
})
|
|
115
|
-
|
|
116
|
-
test('mutex - error propagates', async function (t) {
|
|
117
|
-
const mutex = new Mutex()
|
|
118
|
-
|
|
119
|
-
let resolveCount = 0
|
|
120
|
-
const rejectErrors = []
|
|
121
|
-
const err = new Error('Stop')
|
|
122
|
-
|
|
123
|
-
for (let i = 0; i < 5; i++) {
|
|
124
|
-
mutex.lock().then(() => resolveCount++, err => rejectErrors.push(err))
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
await mutex.destroy(err)
|
|
128
|
-
|
|
129
|
-
try {
|
|
130
|
-
await mutex.lock()
|
|
131
|
-
} catch (e) {
|
|
132
|
-
t.ok(e === err)
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
t.is(resolveCount, 1)
|
|
136
|
-
t.alike(rejectErrors, [err, err, err, err])
|
|
137
|
-
})
|