@fireproof/core 0.0.1

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.
@@ -0,0 +1,725 @@
1
+ import { describe, it } from 'mocha'
2
+ import assert from 'node:assert'
3
+ import { advance, EventBlock, findCommonAncestorWithSortedEvents, findUnknownSortedEvents, decodeEventBlock, findEventsToSync } from '../src/clock.js'
4
+ // import { vis } from '../src/clock.js'
5
+ import { Blockstore, seqEventData, setSeq } from './helpers.js'
6
+
7
+ async function visHead (blocks, head) {
8
+ // const values =
9
+ head.map(async (cid) => {
10
+ const block = await blocks.get(cid)
11
+ return (await decodeEventBlock(block.bytes)).value?.data?.value
12
+ })
13
+ // console.log('visHead', head, await Promise.all(values))
14
+ }
15
+
16
+ async function makeNext (blocks, parent, eventData) {
17
+ const event = await EventBlock.create(eventData, parent)
18
+ await blocks.put(event.cid, event.bytes)
19
+ const head = await advance(blocks, parent, event.cid)
20
+ return { event, head }
21
+ }
22
+
23
+ describe('Clock', () => {
24
+ it('create a new clock', async () => {
25
+ const blocks = new Blockstore()
26
+ // don't do this, create it with the first data block
27
+ const event = await EventBlock.create({})
28
+
29
+ await blocks.put(event.cid, event.bytes)
30
+ const head = await advance(blocks, [], event.cid)
31
+
32
+ // for await (const line of vis(blocks, head)) console.log(line)
33
+ assert.equal(head.length, 1)
34
+ assert.equal(head[0].toString(), event.cid.toString())
35
+
36
+ const sinceHead = head
37
+ const toSync = await findUnknownSortedEvents(blocks, sinceHead, await findCommonAncestorWithSortedEvents(blocks, sinceHead))
38
+ assert.equal(toSync.length, 0)
39
+ })
40
+
41
+ it('add events sequentially', async () => {
42
+ setSeq(0)
43
+ const blocks = new Blockstore()
44
+ const emptyhead = [] // this makes head0 the root
45
+
46
+ /*
47
+ * Create event0 for alice, with emptyhead as parent
48
+ */
49
+ const { event: event0, head: head0 } = await makeNext(blocks, emptyhead, seqEventData('alice'))
50
+ assert(head0.length, 1)
51
+ assert.equal(head0[0].toString(), event0.cid.toString())
52
+
53
+ /*
54
+ * Create event1 for bob, with head0 as parent
55
+ */
56
+ const { event: event1, head: head1 } = await makeNext(blocks, head0, seqEventData('bob'))
57
+
58
+ assert.equal(head1.length, 1)
59
+ assert.equal(head1[0].toString(), event1.cid.toString())
60
+
61
+ const toSync1 = await findEventsToSync(blocks, head1)
62
+
63
+ assert.equal(toSync1.length, 0)
64
+
65
+ /*
66
+ * Create event2 for carol, with head1 as parent
67
+ */
68
+ const { event: event2, head: head2 } = await makeNext(blocks, head1, seqEventData('carol'))
69
+
70
+ assert.equal(head2.length, 1)
71
+ assert.equal(head2[0].toString(), event2.cid.toString())
72
+
73
+ const toSync2 = await findEventsToSync(blocks, head2)
74
+ assert.equal(toSync2.length, 0)
75
+
76
+ const toSync1b = await findEventsToSync(blocks, [...head2, ...head0])
77
+
78
+ assert.equal(toSync1b.length, 2)
79
+ assert.equal(toSync1b[0].value.data.value, 'event1bob')
80
+ assert.equal(toSync1b[1].value.data.value, 'event2carol')
81
+
82
+ /*
83
+ * Create event3 for dave, with head2 as parent
84
+ */
85
+
86
+ const { event: event3, head: head3 } = await makeNext(blocks, head2, seqEventData('dave'))
87
+
88
+ assert.equal(head3.length, 1)
89
+ assert.equal(head3[0].toString(), event3.cid.toString())
90
+
91
+ const toSync3 = await findEventsToSync(blocks, [...head3, ...head0])
92
+ assert.equal(toSync3.length, 3)
93
+ assert.equal(toSync3[0].value.data.value, 'event1bob')
94
+ assert.equal(toSync3[1].value.data.value, 'event2carol')
95
+ assert.equal(toSync3[2].value.data.value, 'event3dave')
96
+
97
+ const toSync3B = await findEventsToSync(blocks, [...head3, ...head1])
98
+ assert.equal(toSync3B.length, 2)
99
+ assert.equal(toSync3B[0].value.data.value, 'event2carol')
100
+ assert.equal(toSync3B[1].value.data.value, 'event3dave')
101
+
102
+ /*
103
+ * Create event4 for eve, with head3 as parent
104
+ */
105
+ const { event: event4, head: head4 } = await makeNext(blocks, head3, seqEventData('eve'))
106
+
107
+ assert.equal(head4.length, 1)
108
+ assert.equal(head4[0].toString(), event4.cid.toString())
109
+
110
+ const toSync4 = await findEventsToSync(blocks, [...head4, ...head0])
111
+ assert.equal(toSync4.length, 4)
112
+ assert.equal(toSync4[0].value.data.value, 'event1bob')
113
+ assert.equal(toSync4[1].value.data.value, 'event2carol')
114
+ assert.equal(toSync4[2].value.data.value, 'event3dave')
115
+ assert.equal(toSync4[3].value.data.value, 'event4eve')
116
+
117
+ const toSync4B = await findEventsToSync(blocks, [...head4, ...head1])
118
+
119
+ assert.equal(toSync4B.length, 3)
120
+ assert.equal(toSync4B[0].value.data.value, 'event2carol')
121
+ assert.equal(toSync4B[1].value.data.value, 'event3dave')
122
+ assert.equal(toSync4B[2].value.data.value, 'event4eve')
123
+
124
+ const toSync4C = await findEventsToSync(blocks, [...head4, ...head2])
125
+
126
+ assert.equal(toSync4C.length, 2)
127
+ assert.equal(toSync4C[0].value.data.value, 'event3dave')
128
+ assert.equal(toSync4C[1].value.data.value, 'event4eve')
129
+
130
+ // don't ask if you already know
131
+ // const toSync4D = await findEventsToSync(blocks, [...head4, ...head3])
132
+ // assert.equal(toSync4D.length, 0)
133
+
134
+ /*
135
+ * Create event5 for frank, with head4 as parent
136
+ */
137
+ const { event: event5, head: head5 } = await makeNext(blocks, head4, seqEventData('frank'))
138
+
139
+ assert.equal(head5.length, 1)
140
+ assert.equal(head5[0].toString(), event5.cid.toString())
141
+ const toSync5 = await findEventsToSync(blocks, [...head5, ...head0])
142
+ assert.equal(toSync5.length, 5)
143
+ assert.equal(toSync5[0].value.data.value, 'event1bob')
144
+ assert.equal(toSync5[1].value.data.value, 'event2carol')
145
+ assert.equal(toSync5[2].value.data.value, 'event3dave')
146
+ assert.equal(toSync5[3].value.data.value, 'event4eve')
147
+ assert.equal(toSync5[4].value.data.value, 'event5frank')
148
+
149
+ const toSync5B = await findEventsToSync(blocks, [...head5, ...head1])
150
+
151
+ assert.equal(toSync5B.length, 4)
152
+ assert.equal(toSync5B[0].value.data.value, 'event2carol')
153
+ assert.equal(toSync5B[1].value.data.value, 'event3dave')
154
+ assert.equal(toSync5B[2].value.data.value, 'event4eve')
155
+ assert.equal(toSync5B[3].value.data.value, 'event5frank')
156
+
157
+ const toSync5C = await findEventsToSync(blocks, [...head5, ...head2])
158
+ assert(toSync5C.length > 0, 'should have 3 events, has ' + toSync5C.length)
159
+ assert.equal(toSync5C[0].value.data.value, 'event3dave')
160
+ assert.equal(toSync5C[1].value.data.value, 'event4eve')
161
+ assert.equal(toSync5C[2].value.data.value, 'event5frank')
162
+
163
+ const toSync5D = await findEventsToSync(blocks, [...head5, ...head3])
164
+ assert.equal(toSync5D.length, 2) // 4
165
+ assert.equal(toSync5D[0].value.data.value, 'event4eve')
166
+ assert.equal(toSync5D[1].value.data.value, 'event5frank')
167
+
168
+ const toSync5E = await findEventsToSync(blocks, [...head5, ...head4])
169
+ assert.equal(toSync5E.length, 1) // 5
170
+ assert.equal(toSync5E[0].value.data.value, 'event5frank')
171
+
172
+ /*
173
+ * Create event6 for grace, with head5 as parent
174
+ */
175
+ const { event: event6, head: head6 } = await makeNext(blocks, head5, seqEventData('grace'))
176
+
177
+ assert.equal(head6.length, 1)
178
+ assert.equal(head6[0].toString(), event6.cid.toString())
179
+
180
+ const toSync6 = await findEventsToSync(blocks, [...head6, ...head0])
181
+ assert.equal(toSync6.length, 6) // 1
182
+ assert.equal(toSync6[0].value.data.value, 'event1bob')
183
+ assert.equal(toSync6[1].value.data.value, 'event2carol')
184
+ assert.equal(toSync6[2].value.data.value, 'event3dave')
185
+ assert.equal(toSync6[3].value.data.value, 'event4eve')
186
+ assert.equal(toSync6[4].value.data.value, 'event5frank')
187
+ assert.equal(toSync6[5].value.data.value, 'event6grace')
188
+
189
+ const toSync6B = await findEventsToSync(blocks, [...head6, ...head1])
190
+ assert.equal(toSync6B.length, 5) // 2
191
+ assert.equal(toSync6B[0].value.data.value, 'event2carol')
192
+ assert.equal(toSync6B[1].value.data.value, 'event3dave')
193
+ assert.equal(toSync6B[2].value.data.value, 'event4eve')
194
+ assert.equal(toSync6B[3].value.data.value, 'event5frank')
195
+ assert.equal(toSync6B[4].value.data.value, 'event6grace')
196
+
197
+ const toSync6C = await findEventsToSync(blocks, [...head6, ...head2])
198
+ assert.equal(toSync6C.length, 4) // 3
199
+ assert.equal(toSync6C[0].value.data.value, 'event3dave')
200
+ assert.equal(toSync6C[1].value.data.value, 'event4eve')
201
+ assert.equal(toSync6C[2].value.data.value, 'event5frank')
202
+ assert.equal(toSync6C[3].value.data.value, 'event6grace')
203
+
204
+ const toSync6D = await findEventsToSync(blocks, [...head6, ...head3])
205
+ assert.equal(toSync6D.length, 3) // 4
206
+ assert.equal(toSync6D[0].value.data.value, 'event4eve')
207
+ assert.equal(toSync6D[1].value.data.value, 'event5frank')
208
+ assert.equal(toSync6D[2].value.data.value, 'event6grace')
209
+
210
+ const toSync6E = await findEventsToSync(blocks, [...head6, ...head4])
211
+ assert.equal(toSync6E.length, 2) // 5
212
+ assert.equal(toSync6E[0].value.data.value, 'event5frank')
213
+ assert.equal(toSync6E[1].value.data.value, 'event6grace')
214
+
215
+ const toSync6F = await findEventsToSync(blocks, [...head6, ...head5])
216
+ assert.equal(toSync6F.length, 1)
217
+ assert.equal(toSync6F[0].value.data.value, 'event6grace')
218
+
219
+ /*
220
+ * Create event7 for grace, with head6 as parent
221
+ */
222
+ const { event: event7, head: head7 } = await makeNext(blocks, head6, seqEventData('holly'))
223
+
224
+ assert.equal(head7.length, 1)
225
+ assert.equal(head7[0].toString(), event7.cid.toString())
226
+
227
+ const toSync7 = await findEventsToSync(blocks, [...head7, ...head0])
228
+ assert.equal(toSync7.length, 7)
229
+ assert.equal(toSync7[0].value.data.value, 'event1bob')
230
+ assert.equal(toSync7[1].value.data.value, 'event2carol')
231
+ assert.equal(toSync7[2].value.data.value, 'event3dave')
232
+ assert.equal(toSync7[3].value.data.value, 'event4eve')
233
+ assert.equal(toSync7[4].value.data.value, 'event5frank')
234
+ assert.equal(toSync7[5].value.data.value, 'event6grace')
235
+ assert.equal(toSync7[6].value.data.value, 'event7holly')
236
+
237
+ const toSync7B = await findEventsToSync(blocks, [...head7, ...head1])
238
+ assert.equal(toSync7B.length, 6)
239
+ assert.equal(toSync7B[0].value.data.value, 'event2carol')
240
+ assert.equal(toSync7B[1].value.data.value, 'event3dave')
241
+ assert.equal(toSync7B[2].value.data.value, 'event4eve')
242
+ assert.equal(toSync7B[3].value.data.value, 'event5frank')
243
+ assert.equal(toSync7B[4].value.data.value, 'event6grace')
244
+
245
+ const toSync7C = await findEventsToSync(blocks, [...head7, ...head2])
246
+ assert.equal(toSync7C.length, 5)
247
+ assert.equal(toSync7C[0].value.data.value, 'event3dave')
248
+ assert.equal(toSync7C[1].value.data.value, 'event4eve')
249
+ assert.equal(toSync7C[2].value.data.value, 'event5frank')
250
+ assert.equal(toSync7C[3].value.data.value, 'event6grace')
251
+ assert.equal(toSync7C[4].value.data.value, 'event7holly')
252
+
253
+ const toSync7D = await findEventsToSync(blocks, [...head7, ...head3])
254
+ assert.equal(toSync7D.length, 4)
255
+ assert.equal(toSync7D[0].value.data.value, 'event4eve')
256
+ assert.equal(toSync7D[1].value.data.value, 'event5frank')
257
+ assert.equal(toSync7D[2].value.data.value, 'event6grace')
258
+ assert.equal(toSync7D[3].value.data.value, 'event7holly')
259
+
260
+ const toSync7E = await findEventsToSync(blocks, [...head7, ...head4])
261
+ assert.equal(toSync7E.length, 3)
262
+ assert.equal(toSync7E[0].value.data.value, 'event5frank')
263
+ assert.equal(toSync7E[1].value.data.value, 'event6grace')
264
+ assert.equal(toSync7E[2].value.data.value, 'event7holly')
265
+
266
+ const toSync7F = await findEventsToSync(blocks, [...head7, ...head5])
267
+ assert.equal(toSync7F.length, 2)
268
+ assert.equal(toSync7F[0].value.data.value, 'event6grace')
269
+ assert.equal(toSync7F[1].value.data.value, 'event7holly')
270
+
271
+ /*
272
+ * Create event8 for isaac, with head7 as parent
273
+ */
274
+ const { event: event8, head: head8 } = await makeNext(blocks, head7, seqEventData('isaac'))
275
+
276
+ assert.equal(head8.length, 1)
277
+ assert.equal(head8[0].toString(), event8.cid.toString())
278
+
279
+ const toSync8 = await findEventsToSync(blocks, [...head8, ...head0])
280
+ assert.equal(toSync8.length, 8)
281
+ assert.equal(toSync8[0].value.data.value, 'event1bob')
282
+ assert.equal(toSync8[1].value.data.value, 'event2carol')
283
+ assert.equal(toSync8[2].value.data.value, 'event3dave')
284
+ assert.equal(toSync8[3].value.data.value, 'event4eve')
285
+ assert.equal(toSync8[4].value.data.value, 'event5frank')
286
+ assert.equal(toSync8[5].value.data.value, 'event6grace')
287
+ assert.equal(toSync8[6].value.data.value, 'event7holly')
288
+ assert.equal(toSync8[7].value.data.value, 'event8isaac')
289
+
290
+ const toSync8B = await findEventsToSync(blocks, [...head8, ...head1])
291
+ assert.equal(toSync8B.length, 7)
292
+ assert.equal(toSync8B[0].value.data.value, 'event2carol')
293
+ assert.equal(toSync8B[1].value.data.value, 'event3dave')
294
+ assert.equal(toSync8B[2].value.data.value, 'event4eve')
295
+ assert.equal(toSync8B[3].value.data.value, 'event5frank')
296
+ assert.equal(toSync8B[4].value.data.value, 'event6grace')
297
+ assert.equal(toSync8B[5].value.data.value, 'event7holly')
298
+ assert.equal(toSync8B[6].value.data.value, 'event8isaac')
299
+
300
+ const toSync8C = await findEventsToSync(blocks, [...head8, ...head2])
301
+ assert.equal(toSync8C.length, 6) // 3
302
+ assert.equal(toSync8C[0].value.data.value, 'event3dave')
303
+ assert.equal(toSync8C[1].value.data.value, 'event4eve')
304
+ assert.equal(toSync8C[2].value.data.value, 'event5frank')
305
+ assert.equal(toSync8C[3].value.data.value, 'event6grace')
306
+ assert.equal(toSync8C[4].value.data.value, 'event7holly')
307
+ assert.equal(toSync8C[5].value.data.value, 'event8isaac')
308
+
309
+ const toSync8D = await findEventsToSync(blocks, [...head8, ...head3])
310
+ assert.equal(toSync8D.length, 5) // 4
311
+ assert.equal(toSync8D[0].value.data.value, 'event4eve')
312
+ assert.equal(toSync8D[1].value.data.value, 'event5frank')
313
+ assert.equal(toSync8D[2].value.data.value, 'event6grace')
314
+ assert.equal(toSync8D[3].value.data.value, 'event7holly')
315
+ assert.equal(toSync8D[4].value.data.value, 'event8isaac')
316
+
317
+ const toSync8E = await findEventsToSync(blocks, [...head8, ...head4])
318
+ assert.equal(toSync8E.length, 4) // 5
319
+ assert.equal(toSync8E[0].value.data.value, 'event5frank')
320
+ assert.equal(toSync8E[1].value.data.value, 'event6grace')
321
+ assert.equal(toSync8E[2].value.data.value, 'event7holly')
322
+ assert.equal(toSync8E[3].value.data.value, 'event8isaac')
323
+
324
+ const toSync8F = await findEventsToSync(blocks, [...head8, ...head5])
325
+ assert.equal(toSync8F.length, 3) // 6
326
+ assert.equal(toSync8F[0].value.data.value, 'event6grace')
327
+ assert.equal(toSync8F[1].value.data.value, 'event7holly')
328
+ assert.equal(toSync8F[2].value.data.value, 'event8isaac')
329
+
330
+ /*
331
+ * Create event9 for jen, with head8 as parent
332
+ */
333
+ const { event: event9, head: head9 } = await makeNext(blocks, head8, seqEventData('jen'))
334
+
335
+ assert.equal(head9.length, 1)
336
+ assert.equal(head9[0].toString(), event9.cid.toString())
337
+
338
+ const toSync9 = await findEventsToSync(blocks, [...head9, ...head0])
339
+ assert.equal(toSync9.length, 9)
340
+ assert.equal(toSync9[0].value.data.value, 'event1bob')
341
+ assert.equal(toSync9[1].value.data.value, 'event2carol')
342
+ assert.equal(toSync9[2].value.data.value, 'event3dave')
343
+ assert.equal(toSync9[3].value.data.value, 'event4eve')
344
+ assert.equal(toSync9[4].value.data.value, 'event5frank')
345
+ assert.equal(toSync9[5].value.data.value, 'event6grace')
346
+ assert.equal(toSync9[6].value.data.value, 'event7holly')
347
+ assert.equal(toSync9[7].value.data.value, 'event8isaac')
348
+ assert.equal(toSync9[8].value.data.value, 'event9jen')
349
+
350
+ const toSync9B = await findEventsToSync(blocks, [...head9, ...head1])
351
+ assert.equal(toSync9B.length, 8)
352
+ assert.equal(toSync9B[0].value.data.value, 'event2carol')
353
+ assert.equal(toSync9B[1].value.data.value, 'event3dave')
354
+ assert.equal(toSync9B[2].value.data.value, 'event4eve')
355
+ assert.equal(toSync9B[3].value.data.value, 'event5frank')
356
+ assert.equal(toSync9B[4].value.data.value, 'event6grace')
357
+ assert.equal(toSync9B[5].value.data.value, 'event7holly')
358
+ assert.equal(toSync9B[6].value.data.value, 'event8isaac')
359
+ assert.equal(toSync9B[7].value.data.value, 'event9jen')
360
+
361
+ const toSync9C = await findEventsToSync(blocks, [...head9, ...head2])
362
+ assert.equal(toSync9C.length, 7)
363
+ assert.equal(toSync9C[0].value.data.value, 'event3dave')
364
+ assert.equal(toSync9C[1].value.data.value, 'event4eve')
365
+ assert.equal(toSync9C[2].value.data.value, 'event5frank')
366
+ assert.equal(toSync9C[3].value.data.value, 'event6grace')
367
+ assert.equal(toSync9C[4].value.data.value, 'event7holly')
368
+ assert.equal(toSync9C[5].value.data.value, 'event8isaac')
369
+ assert.equal(toSync9C[6].value.data.value, 'event9jen')
370
+
371
+ const toSync9D = await findEventsToSync(blocks, [...head9, ...head3])
372
+ assert.equal(toSync9D.length, 6)
373
+ assert.equal(toSync9D[0].value.data.value, 'event4eve')
374
+ assert.equal(toSync9D[1].value.data.value, 'event5frank')
375
+ assert.equal(toSync9D[2].value.data.value, 'event6grace')
376
+ assert.equal(toSync9D[3].value.data.value, 'event7holly')
377
+ assert.equal(toSync9D[4].value.data.value, 'event8isaac')
378
+ assert.equal(toSync9D[5].value.data.value, 'event9jen')
379
+
380
+ const toSync9E = await findEventsToSync(blocks, [...head9, ...head4])
381
+ assert.equal(toSync9E.length, 5)
382
+ assert.equal(toSync9E[0].value.data.value, 'event5frank')
383
+ assert.equal(toSync9E[1].value.data.value, 'event6grace')
384
+ assert.equal(toSync9E[2].value.data.value, 'event7holly')
385
+ assert.equal(toSync9E[3].value.data.value, 'event8isaac')
386
+ assert.equal(toSync9E[4].value.data.value, 'event9jen')
387
+
388
+ // for await (const line of vis(blocks, head8)) console.log(line)
389
+ })
390
+
391
+ it('add two events with shared parents', async () => {
392
+ setSeq(-1)
393
+ const blocks = new Blockstore()
394
+ const root = await EventBlock.create(seqEventData('root'))
395
+ await blocks.put(root.cid, root.bytes)
396
+
397
+ /** @type {import('../src/clock').EventLink<any>[]} */
398
+ let head = await advance(blocks, [], root.cid)
399
+ assert.equal(head.length, 1)
400
+ assert.equal(head[0], root.cid)
401
+
402
+ const parents = head
403
+
404
+ const event0 = await EventBlock.create(seqEventData(), parents)
405
+ await blocks.put(event0.cid, event0.bytes)
406
+
407
+ head = await advance(blocks, parents, event0.cid)
408
+ const head0 = head
409
+
410
+ const event1 = await EventBlock.create(seqEventData(), parents)
411
+ await blocks.put(event1.cid, event1.bytes)
412
+ head = await advance(blocks, head, event1.cid)
413
+ const head1 = head
414
+
415
+ // for await (const line of vis(blocks, head)) console.log(line)
416
+ assert.equal(head.length, 2)
417
+ assert.equal(head[0].toString(), event0.cid.toString())
418
+ assert.equal(head[1].toString(), event1.cid.toString())
419
+
420
+ let sinceHead = head1
421
+ let toSync = await findUnknownSortedEvents(blocks, sinceHead, await findCommonAncestorWithSortedEvents(blocks, sinceHead))
422
+ // assert.equal(toSync.length, 1) // 0
423
+ // assert.equal(toSync[0].cid.toString(), event0.cid.toString())
424
+
425
+ const event2 = await EventBlock.create(seqEventData(), head1)
426
+ await blocks.put(event2.cid, event2.bytes)
427
+ head = await advance(blocks, head, event2.cid)
428
+ const head2 = head
429
+
430
+ assert.equal(head.length, 1)
431
+
432
+ sinceHead = head2
433
+ toSync = await findUnknownSortedEvents(blocks, sinceHead, await findCommonAncestorWithSortedEvents(blocks, sinceHead))
434
+ assert.equal(toSync.length, 0)
435
+
436
+ // todo do these since heads make sense?
437
+ sinceHead = [...head0, ...head2]
438
+ toSync = await findUnknownSortedEvents(blocks, sinceHead, await findCommonAncestorWithSortedEvents(blocks, sinceHead))
439
+ // console.log('need', toSync.map(b => b.value.data))
440
+ // assert.equal(toSync.length, 2) // 0
441
+ // assert.equal(toSync[0].cid.toString(), event1.cid.toString())
442
+ // assert.equal(toSync[1].cid.toString(), event2.cid.toString())
443
+ })
444
+
445
+ it('add two events with some shared parents', async () => {
446
+ const blocks = new Blockstore()
447
+ const root = await EventBlock.create(seqEventData())
448
+ await blocks.put(root.cid, root.bytes)
449
+
450
+ /** @type {import('../src/clock').EventLink<any>[]} */
451
+ let head = [root.cid]
452
+ const parents0 = head
453
+
454
+ const event0 = await EventBlock.create(seqEventData(), parents0)
455
+ await blocks.put(event0.cid, event0.bytes)
456
+ head = await advance(blocks, head, event0.cid)
457
+
458
+ const event1 = await EventBlock.create(seqEventData(), parents0)
459
+ await blocks.put(event1.cid, event1.bytes)
460
+ head = await advance(blocks, head, event1.cid)
461
+
462
+ const event2 = await EventBlock.create(seqEventData(), parents0)
463
+ await blocks.put(event2.cid, event2.bytes)
464
+ head = await advance(blocks, head, event2.cid)
465
+
466
+ const event3 = await EventBlock.create(seqEventData(), [event0.cid, event1.cid])
467
+ await blocks.put(event3.cid, event3.bytes)
468
+ head = await advance(blocks, head, event3.cid)
469
+ // const parentz = head
470
+
471
+ const event4 = await EventBlock.create(seqEventData(), [event2.cid])
472
+ await blocks.put(event4.cid, event4.bytes)
473
+ head = await advance(blocks, head, event4.cid)
474
+
475
+ // console.log('add two events with some shared parents')
476
+ // for await (const line of vis(blocks, head)) console.log(line)
477
+ assert.equal(head.length, 2)
478
+ assert.equal(head[0].toString(), event3.cid.toString())
479
+ assert.equal(head[1].toString(), event4.cid.toString())
480
+ // console.log('since', parentz)
481
+ // for await (const block of since(blocks, parentz)) {
482
+ // if (block?.value) console.log(block.value.data)
483
+ // }
484
+ // const { ancestor, sorted } = await findCommonAncestorWithSortedEvents(blocks, parentz)
485
+ // console.log('findCommonAncestorWithSortedEvents', ancestor, sorted.map(b => b.value.data))
486
+ })
487
+
488
+ it('converge when multi-root', async () => {
489
+ setSeq(-1)
490
+ const blocks = new Blockstore()
491
+ const root = await EventBlock.create(seqEventData())
492
+ await blocks.put(root.cid, root.bytes)
493
+
494
+ /** @type {import('../src/clock').EventLink<any>[]} */
495
+ let head = [root.cid]
496
+ const parents0 = head
497
+
498
+ const event0 = await EventBlock.create(seqEventData(), parents0)
499
+ await blocks.put(event0.cid, event0.bytes)
500
+ head = await advance(blocks, head, event0.cid)
501
+
502
+ const event1 = await EventBlock.create(seqEventData(), parents0)
503
+ await blocks.put(event1.cid, event1.bytes)
504
+ head = await advance(blocks, head, event1.cid)
505
+
506
+ const event1head = head
507
+
508
+ const event2 = await EventBlock.create(seqEventData(), event1head)
509
+ await blocks.put(event2.cid, event2.bytes)
510
+ head = await advance(blocks, head, event2.cid)
511
+
512
+ const event3 = await EventBlock.create(seqEventData(), event1head)
513
+ await blocks.put(event3.cid, event3.bytes)
514
+ head = await advance(blocks, head, event3.cid)
515
+
516
+ const event3head = head
517
+
518
+ const event4 = await EventBlock.create(seqEventData(), event1head)
519
+ await blocks.put(event4.cid, event4.bytes)
520
+ head = await advance(blocks, head, event4.cid)
521
+ const event4head = head
522
+ await visHead(blocks, event4head)
523
+
524
+ const event5 = await EventBlock.create(seqEventData(), event3head)
525
+ await blocks.put(event5.cid, event5.bytes)
526
+ head = await advance(blocks, head, event5.cid)
527
+ const event5head = head
528
+ await visHead(blocks, event5head)
529
+
530
+ const event6 = await EventBlock.create(seqEventData(), event5head)
531
+ await blocks.put(event6.cid, event6.bytes)
532
+ head = await advance(blocks, head, event6.cid)
533
+ const event6head = head
534
+ await visHead(blocks, event6head)
535
+
536
+ const event7 = await EventBlock.create(seqEventData(), event6head)
537
+ await blocks.put(event7.cid, event7.bytes)
538
+ head = await advance(blocks, head, event7.cid)
539
+ const event7head = head
540
+ await visHead(blocks, event7head)
541
+
542
+ const event8 = await EventBlock.create(seqEventData(), event7head)
543
+ await blocks.put(event8.cid, event8.bytes)
544
+ head = await advance(blocks, head, event8.cid)
545
+ const event8head = head
546
+ await visHead(blocks, event8head)
547
+
548
+ const event9 = await EventBlock.create(seqEventData(), event7head)
549
+ await blocks.put(event9.cid, event9.bytes)
550
+ head = await advance(blocks, head, event9.cid)
551
+ const event9head = head
552
+ await visHead(blocks, event9head)
553
+
554
+ const event10 = await EventBlock.create(seqEventData(), event9head)
555
+ await blocks.put(event10.cid, event10.bytes)
556
+ head = await advance(blocks, head, event10.cid)
557
+ const event10head = head
558
+ await visHead(blocks, event10head)
559
+
560
+ // console.log('converge when multi-root')
561
+ // for await (const line of vis(blocks, event10head)) console.log(line)
562
+
563
+ assert.equal(event10head.length, 1)
564
+ assert.equal(event10head[0].toString(), event10.cid.toString())
565
+
566
+ // todo do these roots make sense?
567
+ // const { ancestor, sorted } = await findCommonAncestorWithSortedEvents(blocks, [event5.cid, event2.cid])
568
+ // const toSync = await findUnknownSortedEvents(blocks, [event5.cid, event2.cid], { ancestor, sorted })
569
+ // assert.equal(toSync.length, 0)
570
+ // assert.equal(toSync[0].value.data.value, 'event3')
571
+ // assert.equal(toSync[1].value.data.value, 'event5')
572
+
573
+ // todo do these roots make sense?
574
+ // const ancestorWithSorted = await findCommonAncestorWithSortedEvents(blocks, [event6.cid, event2.cid])
575
+ // const toSync2 = await findUnknownSortedEvents(blocks, [event6.cid, event2.cid], ancestorWithSorted)
576
+ // assert.equal(toSync2.length, 0)
577
+
578
+ // assert.equal(toSync2[0].value.data.value, 'event3')
579
+ // assert.equal(toSync2[1].value.data.value, 'event5')
580
+ // assert.equal(toSync2[2].value.data.value, 'event4')
581
+ // assert.equal(toSync2[3].value.data.value, 'event6')
582
+ // const ancestorBlock = await blocks.get(ancestor)
583
+ // const ancestorDecoded = await decodeEventBlock(ancestorBlock.bytes)
584
+ const ancestorWithSorted2 = await findCommonAncestorWithSortedEvents(blocks, [event7.cid, event10.cid])
585
+ const toSync3 = await findUnknownSortedEvents(blocks, [event7.cid, event10.cid], ancestorWithSorted2)
586
+ assert.equal(toSync3[0].value.data.value, 'event9')
587
+ assert.equal(toSync3[1].value.data.value, 'event8')
588
+ assert.equal(toSync3[2].value.data.value, 'event10')
589
+ })
590
+
591
+ it('add an old event', async () => {
592
+ const blocks = new Blockstore()
593
+ const root = await EventBlock.create(seqEventData())
594
+ await blocks.put(root.cid, root.bytes)
595
+
596
+ /** @type {import('../src/clock').EventLink<any>[]} */
597
+ let head = [root.cid]
598
+ const parents0 = head
599
+
600
+ const event0 = await EventBlock.create(seqEventData(), parents0)
601
+ await blocks.put(event0.cid, event0.bytes)
602
+ head = await advance(blocks, head, event0.cid)
603
+
604
+ const event1 = await EventBlock.create(seqEventData(), parents0)
605
+ await blocks.put(event1.cid, event1.bytes)
606
+ head = await advance(blocks, head, event1.cid)
607
+
608
+ const event1head = head
609
+
610
+ const event2 = await EventBlock.create(seqEventData(), event1head)
611
+ await blocks.put(event2.cid, event2.bytes)
612
+ head = await advance(blocks, head, event2.cid)
613
+
614
+ const event3 = await EventBlock.create(seqEventData(), event1head)
615
+ await blocks.put(event3.cid, event3.bytes)
616
+ head = await advance(blocks, head, event3.cid)
617
+
618
+ const event4 = await EventBlock.create(seqEventData(), event1head)
619
+ await blocks.put(event4.cid, event4.bytes)
620
+ head = await advance(blocks, head, event4.cid)
621
+
622
+ const parents2 = head
623
+
624
+ const event5 = await EventBlock.create(seqEventData(), parents2)
625
+ await blocks.put(event5.cid, event5.bytes)
626
+ head = await advance(blocks, head, event5.cid)
627
+
628
+ // now very old one
629
+ const event6 = await EventBlock.create(seqEventData(), parents0)
630
+ await blocks.put(event6.cid, event6.bytes)
631
+ head = await advance(blocks, head, event6.cid)
632
+
633
+ // for await (const line of vis(blocks, head)) console.log(line)
634
+ assert.equal(head.length, 2)
635
+ assert.equal(head[0].toString(), event5.cid.toString())
636
+ assert.equal(head[1].toString(), event6.cid.toString())
637
+ })
638
+
639
+ it('add an event with missing parents', async () => {
640
+ setSeq(-1)
641
+ const blocks = new Blockstore()
642
+ const root = await EventBlock.create(seqEventData())
643
+ await blocks.put(root.cid, root.bytes)
644
+
645
+ /** @type {import('../src/clock').EventLink<any>[]} */
646
+ let head = [root.cid]
647
+
648
+ const event0 = await EventBlock.create(seqEventData(), head)
649
+ await blocks.put(event0.cid, event0.bytes)
650
+
651
+ const event1 = await EventBlock.create(seqEventData(), [event0.cid])
652
+ await blocks.put(event1.cid, event1.bytes)
653
+
654
+ head = await advance(blocks, head, event1.cid)
655
+
656
+ // for await (const line of vis(blocks, head)) console.log(line)
657
+ assert.equal(head.length, 1)
658
+ assert.equal(head[0].toString(), event1.cid.toString())
659
+ })
660
+
661
+ it('reproduce the issue from fireproof docs since update test', async () => {
662
+ setSeq(-1)
663
+ const blocks = new Blockstore()
664
+ // alice
665
+ const root = await EventBlock.create(seqEventData('alice'))
666
+ await blocks.put(root.cid, root.bytes)
667
+ let head = await advance(blocks, [], root.cid)
668
+ const roothead = head
669
+ // db root
670
+ let sinceHead = [...roothead]
671
+ let toSync = await findUnknownSortedEvents(blocks, sinceHead, await findCommonAncestorWithSortedEvents(blocks, sinceHead))
672
+ assert.equal(toSync.length, 0) // we use all docs for first query in Fireproof
673
+
674
+ // create bob
675
+ const event0 = await EventBlock.create(seqEventData('bob'), head)
676
+ await blocks.put(event0.cid, event0.bytes)
677
+ // console.log('new event0', event0.cid)
678
+
679
+ head = await advance(blocks, head, event0.cid)
680
+
681
+ const event0head = head
682
+ sinceHead = event0head
683
+ toSync = await findUnknownSortedEvents(blocks, sinceHead, await findCommonAncestorWithSortedEvents(blocks, sinceHead))
684
+ assert.equal(toSync.length, 0)
685
+
686
+ sinceHead = [...roothead, ...event0head]
687
+ toSync = await findUnknownSortedEvents(blocks, sinceHead, await findCommonAncestorWithSortedEvents(blocks, sinceHead))
688
+ assert.equal(toSync.length, 1)
689
+
690
+ // create carol
691
+ const event1 = await EventBlock.create(seqEventData('carol'), head)
692
+ await blocks.put(event1.cid, event1.bytes)
693
+ head = await advance(blocks, head, event1.cid)
694
+ const event1head = head
695
+
696
+ sinceHead = [...event0head, ...event1head]
697
+ // sinceHead = event0head
698
+ const sigil = await findCommonAncestorWithSortedEvents(blocks, sinceHead)
699
+ // console.log('ancestor', (await decodeEventBlock((await blocks.get(sigil.ancestor)).bytes)).value)
700
+
701
+ toSync = await findUnknownSortedEvents(blocks, sinceHead, sigil)
702
+
703
+ assert.equal(toSync.length, 1)
704
+
705
+ // for await (const line of vis(blocks, head)) console.log(line)
706
+
707
+ sinceHead = [...event1head, ...roothead]
708
+ toSync = await findUnknownSortedEvents(blocks, sinceHead, await findCommonAncestorWithSortedEvents(blocks, sinceHead))
709
+
710
+ assert.equal(toSync.length, 2)
711
+
712
+ const event2 = await EventBlock.create(seqEventData('xxx'), head)
713
+ await blocks.put(event2.cid, event2.bytes)
714
+ head = await advance(blocks, head, event2.cid)
715
+ const event2head = head
716
+
717
+ sinceHead = [...event2head, ...event0head]
718
+ toSync = await findUnknownSortedEvents(blocks, sinceHead, await findCommonAncestorWithSortedEvents(blocks, sinceHead))
719
+ assert.equal(toSync.length, 2)
720
+
721
+ sinceHead = [...event2head, ...event1head]
722
+ toSync = await findUnknownSortedEvents(blocks, sinceHead, await findCommonAncestorWithSortedEvents(blocks, sinceHead))
723
+ assert.equal(toSync.length, 1)
724
+ })
725
+ })