@subsquid/batch-processor 0.2.0-portal-api.493495 → 0.2.0-portal-api.19316d

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,651 @@
1
+ /// <reference types="mocha" />
2
+ import assert from 'assert'
3
+ import {TemplateRegistry} from './template-registry'
4
+
5
+
6
+ function values(reg: TemplateRegistry, key: string) {
7
+ return reg.get(key).map((e) => ({value: e.value, from: e.range.from, to: e.range.to}))
8
+ }
9
+
10
+
11
+ describe('TemplateRegistry', function () {
12
+ describe('apply (add)', function () {
13
+ it('new value returns true', function () {
14
+ let reg = new TemplateRegistry()
15
+ let changed = reg.apply({type: 'add', key: 'log', value: '0xabc', blockNumber: 100})
16
+ assert.strictEqual(changed, true)
17
+ assert.deepStrictEqual(values(reg, 'log'), [{value: '0xabc', from: 100, to: undefined}])
18
+ })
19
+
20
+ it('duplicate add with same from returns false', function () {
21
+ let reg = new TemplateRegistry()
22
+ reg.apply({type: 'add', key: 'log', value: '0xabc', blockNumber: 100})
23
+ let changed = reg.apply({type: 'add', key: 'log', value: '0xabc', blockNumber: 100})
24
+ assert.strictEqual(changed, false)
25
+ })
26
+
27
+ it('duplicate add with later from returns false', function () {
28
+ let reg = new TemplateRegistry()
29
+ reg.apply({type: 'add', key: 'log', value: '0xabc', blockNumber: 100})
30
+ let changed = reg.apply({type: 'add', key: 'log', value: '0xabc', blockNumber: 200})
31
+ assert.strictEqual(changed, false)
32
+ assert.deepStrictEqual(values(reg, 'log'), [{value: '0xabc', from: 100, to: undefined}])
33
+ })
34
+
35
+ it('add with earlier from widens range', function () {
36
+ let reg = new TemplateRegistry()
37
+ reg.apply({type: 'add', key: 'log', value: '0xabc', blockNumber: 100})
38
+ let changed = reg.apply({type: 'add', key: 'log', value: '0xabc', blockNumber: 50})
39
+ assert.strictEqual(changed, true)
40
+ assert.deepStrictEqual(values(reg, 'log'), [{value: '0xabc', from: 50, to: undefined}])
41
+ })
42
+
43
+ it('multiple values under same key', function () {
44
+ let reg = new TemplateRegistry()
45
+ reg.apply({type: 'add', key: 'log', value: '0xabc', blockNumber: 100})
46
+ reg.apply({type: 'add', key: 'log', value: '0xdef', blockNumber: 200})
47
+ assert.deepStrictEqual(values(reg, 'log'), [
48
+ {value: '0xabc', from: 100, to: undefined},
49
+ {value: '0xdef', from: 200, to: undefined},
50
+ ])
51
+ })
52
+
53
+ it('different keys are independent', function () {
54
+ let reg = new TemplateRegistry()
55
+ reg.apply({type: 'add', key: 'log', value: '0xabc', blockNumber: 100})
56
+ reg.apply({type: 'add', key: 'instruction', value: '0xabc', blockNumber: 200})
57
+ assert.deepStrictEqual(values(reg, 'log'), [{value: '0xabc', from: 100, to: undefined}])
58
+ assert.deepStrictEqual(values(reg, 'instruction'), [{value: '0xabc', from: 200, to: undefined}])
59
+ })
60
+ })
61
+
62
+ describe('apply (delete)', function () {
63
+ it('deactivating active entry returns true', function () {
64
+ let reg = new TemplateRegistry()
65
+ reg.apply({type: 'add', key: 'log', value: '0xabc', blockNumber: 100})
66
+ let changed = reg.apply({type: 'delete', key: 'log', value: '0xabc', blockNumber: 500})
67
+ assert.strictEqual(changed, true)
68
+ assert.deepStrictEqual(values(reg, 'log'), [{value: '0xabc', from: 100, to: 500}])
69
+ })
70
+
71
+ it('deactivating already deleted entry returns false', function () {
72
+ let reg = new TemplateRegistry()
73
+ reg.apply({type: 'add', key: 'log', value: '0xabc', blockNumber: 100})
74
+ reg.apply({type: 'delete', key: 'log', value: '0xabc', blockNumber: 500})
75
+ let changed = reg.apply({type: 'delete', key: 'log', value: '0xabc', blockNumber: 500})
76
+ assert.strictEqual(changed, false)
77
+ })
78
+
79
+ it('deactivating unknown value returns false', function () {
80
+ let reg = new TemplateRegistry()
81
+ let changed = reg.apply({type: 'delete', key: 'log', value: '0xabc', blockNumber: 500})
82
+ assert.strictEqual(changed, false)
83
+ })
84
+
85
+ it('deactivating unknown key returns false', function () {
86
+ let reg = new TemplateRegistry()
87
+ reg.apply({type: 'add', key: 'log', value: '0xabc', blockNumber: 100})
88
+ let changed = reg.apply({type: 'delete', key: 'other', value: '0xabc', blockNumber: 500})
89
+ assert.strictEqual(changed, false)
90
+ })
91
+
92
+ it('stale deactivation (to < from) is ignored', function () {
93
+ let reg = new TemplateRegistry()
94
+ reg.apply({type: 'add', key: 'log', value: '0xabc', blockNumber: 100})
95
+ let changed = reg.apply({type: 'delete', key: 'log', value: '0xabc', blockNumber: 50})
96
+ assert.strictEqual(changed, false)
97
+ assert.deepStrictEqual(values(reg, 'log'), [{value: '0xabc', from: 100, to: undefined}])
98
+ })
99
+ })
100
+
101
+ describe('re-activation', function () {
102
+ it('re-activation with from >= to creates new range', function () {
103
+ let reg = new TemplateRegistry()
104
+ reg.apply({type: 'add', key: 'log', value: '0xabc', blockNumber: 100})
105
+ reg.apply({type: 'delete', key: 'log', value: '0xabc', blockNumber: 500})
106
+ let changed = reg.apply({type: 'add', key: 'log', value: '0xabc', blockNumber: 500})
107
+ assert.strictEqual(changed, true)
108
+ assert.deepStrictEqual(values(reg, 'log'), [
109
+ {value: '0xabc', from: 100, to: 500},
110
+ {value: '0xabc', from: 500, to: undefined},
111
+ ])
112
+ })
113
+
114
+ it('re-activation with from < to returns false', function () {
115
+ let reg = new TemplateRegistry()
116
+ reg.apply({type: 'add', key: 'log', value: '0xabc', blockNumber: 100})
117
+ reg.apply({type: 'delete', key: 'log', value: '0xabc', blockNumber: 500})
118
+ let changed = reg.apply({type: 'add', key: 'log', value: '0xabc', blockNumber: 300})
119
+ assert.strictEqual(changed, false)
120
+ assert.deepStrictEqual(values(reg, 'log'), [{value: '0xabc', from: 100, to: 500}])
121
+ })
122
+
123
+ it('re-activation after re-activation is idempotent', function () {
124
+ let reg = new TemplateRegistry()
125
+ reg.apply({type: 'add', key: 'log', value: '0xabc', blockNumber: 100})
126
+ reg.apply({type: 'delete', key: 'log', value: '0xabc', blockNumber: 500})
127
+ reg.apply({type: 'add', key: 'log', value: '0xabc', blockNumber: 600})
128
+ let changed = reg.apply({type: 'add', key: 'log', value: '0xabc', blockNumber: 600})
129
+ assert.strictEqual(changed, false)
130
+ })
131
+
132
+ it('multiple deactivation/re-activation cycles', function () {
133
+ let reg = new TemplateRegistry()
134
+ reg.apply({type: 'add', key: 'log', value: '0xabc', blockNumber: 100})
135
+ reg.apply({type: 'delete', key: 'log', value: '0xabc', blockNumber: 500})
136
+ reg.apply({type: 'add', key: 'log', value: '0xabc', blockNumber: 600})
137
+ reg.apply({type: 'delete', key: 'log', value: '0xabc', blockNumber: 900})
138
+ reg.apply({type: 'add', key: 'log', value: '0xabc', blockNumber: 1000})
139
+ assert.deepStrictEqual(values(reg, 'log'), [
140
+ {value: '0xabc', from: 100, to: 500},
141
+ {value: '0xabc', from: 600, to: 900},
142
+ {value: '0xabc', from: 1000, to: undefined},
143
+ ])
144
+ })
145
+ })
146
+
147
+ describe('apply (add + delete combined)', function () {
148
+ it('add and delete same value', function () {
149
+ let reg = new TemplateRegistry()
150
+ reg.apply({type: 'add', key: 'log', value: '0xabc', blockNumber: 100})
151
+ reg.apply({type: 'delete', key: 'log', value: '0xabc', blockNumber: 500})
152
+ assert.deepStrictEqual(values(reg, 'log'), [{value: '0xabc', from: 100, to: 500}])
153
+ })
154
+ })
155
+
156
+ describe('transact', function () {
157
+ let range = {from: 0, to: 1000}
158
+
159
+ it('returns pending data and changed flag', async function () {
160
+ let reg = new TemplateRegistry()
161
+ let result = await reg.transact(range, async (t) => {
162
+ t.add('log', '0xabc', 100)
163
+ })
164
+ assert.strictEqual(result.changed, true)
165
+ assert.deepStrictEqual(result.data, [{type: 'add', key: 'log', value: '0xabc', blockNumber: 100}])
166
+ })
167
+
168
+ it('commits on success', async function () {
169
+ let reg = new TemplateRegistry()
170
+ await reg.transact(range, async (t) => {
171
+ t.add('log', '0xabc', 100)
172
+ })
173
+ let result = await reg.transact(range, async () => {})
174
+ assert.strictEqual(result.changed, false)
175
+ assert.deepStrictEqual(result.data, [])
176
+ })
177
+
178
+ it('rolls back on error', async function () {
179
+ let reg = new TemplateRegistry()
180
+ await assert.rejects(
181
+ reg.transact(range, async (t) => {
182
+ t.add('log', '0xabc', 100)
183
+ throw new Error('fail')
184
+ })
185
+ )
186
+ assert.deepStrictEqual(values(reg, 'log'), [])
187
+ })
188
+
189
+ it('rolls back delete on error', async function () {
190
+ let reg = new TemplateRegistry()
191
+ await reg.transact(range, async (t) => {
192
+ t.add('log', '0xabc', 100)
193
+ })
194
+ await assert.rejects(
195
+ reg.transact(range, async (t) => {
196
+ t.remove('log', '0xabc', 500)
197
+ throw new Error('fail')
198
+ })
199
+ )
200
+ assert.deepStrictEqual(values(reg, 'log'), [{value: '0xabc', from: 100, to: undefined}])
201
+ })
202
+
203
+ it('rolls back range widening on error', async function () {
204
+ let reg = new TemplateRegistry()
205
+ await reg.transact(range, async (t) => {
206
+ t.add('log', '0xabc', 100)
207
+ })
208
+ await assert.rejects(
209
+ reg.transact(range, async (t) => {
210
+ t.add('log', '0xabc', 50)
211
+ throw new Error('fail')
212
+ })
213
+ )
214
+ assert.deepStrictEqual(values(reg, 'log'), [{value: '0xabc', from: 100, to: undefined}])
215
+ })
216
+
217
+ it('rolls back re-activation on error', async function () {
218
+ let reg = new TemplateRegistry()
219
+ await reg.transact(range, async (t) => {
220
+ t.add('log', '0xabc', 100)
221
+ t.remove('log', '0xabc', 500)
222
+ })
223
+ await assert.rejects(
224
+ reg.transact(range, async (t) => {
225
+ t.add('log', '0xabc', 600)
226
+ throw new Error('fail')
227
+ })
228
+ )
229
+ assert.deepStrictEqual(values(reg, 'log'), [{value: '0xabc', from: 100, to: 500}])
230
+ })
231
+
232
+ it('rolls back multiple operations on error', async function () {
233
+ let reg = new TemplateRegistry()
234
+ await assert.rejects(
235
+ reg.transact(range, async (t) => {
236
+ t.add('log', '0xabc', 100)
237
+ t.add('log', '0xdef', 200)
238
+ throw new Error('fail')
239
+ })
240
+ )
241
+ assert.deepStrictEqual(values(reg, 'log'), [])
242
+ })
243
+
244
+ it('returns data even when registry already has the values', async function () {
245
+ let reg = new TemplateRegistry()
246
+ await reg.transact(range, async (t) => {
247
+ t.add('log', '0xabc', 100)
248
+ })
249
+ let result = await reg.transact(range, async (t) => {
250
+ t.add('log', '0xabc', 100)
251
+ })
252
+ assert.strictEqual(result.changed, false)
253
+ assert.deepStrictEqual(result.data, [{type: 'add', key: 'log', value: '0xabc', blockNumber: 100}])
254
+ })
255
+
256
+ it('rejects blockNumber before batch start', async function () {
257
+ let reg = new TemplateRegistry()
258
+ await assert.rejects(
259
+ reg.transact({from: 100, to: 200}, async (t) => {
260
+ t.add('log', '0xabc', 50)
261
+ }),
262
+ RangeError
263
+ )
264
+ })
265
+ })
266
+
267
+ describe('has', function () {
268
+ it('returns true for active value at block', function () {
269
+ let reg = new TemplateRegistry()
270
+ reg.apply({type: 'add', key: 'log', value: '0xabc', blockNumber: 100})
271
+ assert.strictEqual(reg.has('log', '0xabc', 150), true)
272
+ })
273
+
274
+ it('returns false before activation block', function () {
275
+ let reg = new TemplateRegistry()
276
+ reg.apply({type: 'add', key: 'log', value: '0xabc', blockNumber: 100})
277
+ assert.strictEqual(reg.has('log', '0xabc', 50), false)
278
+ })
279
+
280
+ it('returns true at exact activation block', function () {
281
+ let reg = new TemplateRegistry()
282
+ reg.apply({type: 'add', key: 'log', value: '0xabc', blockNumber: 100})
283
+ assert.strictEqual(reg.has('log', '0xabc', 100), true)
284
+ })
285
+
286
+ it('returns true at deactivation block', function () {
287
+ let reg = new TemplateRegistry()
288
+ reg.apply({type: 'add', key: 'log', value: '0xabc', blockNumber: 100})
289
+ reg.apply({type: 'delete', key: 'log', value: '0xabc', blockNumber: 500})
290
+ assert.strictEqual(reg.has('log', '0xabc', 500), true)
291
+ })
292
+
293
+ it('returns false after deactivation block', function () {
294
+ let reg = new TemplateRegistry()
295
+ reg.apply({type: 'add', key: 'log', value: '0xabc', blockNumber: 100})
296
+ reg.apply({type: 'delete', key: 'log', value: '0xabc', blockNumber: 500})
297
+ assert.strictEqual(reg.has('log', '0xabc', 501), false)
298
+ })
299
+
300
+ it('returns false for unknown key', function () {
301
+ let reg = new TemplateRegistry()
302
+ assert.strictEqual(reg.has('log', '0xabc', 100), false)
303
+ })
304
+
305
+ it('returns false for unknown value', function () {
306
+ let reg = new TemplateRegistry()
307
+ reg.apply({type: 'add', key: 'log', value: '0xabc', blockNumber: 100})
308
+ assert.strictEqual(reg.has('log', '0xdef', 100), false)
309
+ })
310
+ })
311
+
312
+ describe('get', function () {
313
+ it('returns empty for unknown key', function () {
314
+ let reg = new TemplateRegistry()
315
+ assert.deepStrictEqual(reg.get('log'), [])
316
+ })
317
+
318
+ it('includes deleted entries with their range', function () {
319
+ let reg = new TemplateRegistry()
320
+ reg.apply({type: 'add', key: 'log', value: '0xabc', blockNumber: 100})
321
+ reg.apply({type: 'add', key: 'log', value: '0xdef', blockNumber: 200})
322
+ reg.apply({type: 'delete', key: 'log', value: '0xabc', blockNumber: 500})
323
+ assert.deepStrictEqual(values(reg, 'log'), [
324
+ {value: '0xabc', from: 100, to: 500},
325
+ {value: '0xdef', from: 200, to: undefined},
326
+ ])
327
+ })
328
+ })
329
+
330
+ describe('init', function () {
331
+ it('rebuilds state from mutations', function () {
332
+ let reg = new TemplateRegistry()
333
+ reg.init([
334
+ {type: 'add', key: 'log', value: '0xabc', blockNumber: 100},
335
+ {type: 'add', key: 'log', value: '0xdef', blockNumber: 200},
336
+ {type: 'delete', key: 'log', value: '0xdef', blockNumber: 500},
337
+ ])
338
+ assert.deepStrictEqual(values(reg, 'log'), [
339
+ {value: '0xabc', from: 100, to: undefined},
340
+ {value: '0xdef', from: 200, to: 500},
341
+ ])
342
+ })
343
+
344
+ it('handles out-of-order mutations by sorting', function () {
345
+ let reg = new TemplateRegistry()
346
+ reg.init([
347
+ {type: 'add', key: 'log', value: '0xabc', blockNumber: 600},
348
+ {type: 'delete', key: 'log', value: '0xabc', blockNumber: 500},
349
+ {type: 'add', key: 'log', value: '0xabc', blockNumber: 100},
350
+ ])
351
+ assert.deepStrictEqual(values(reg, 'log'), [
352
+ {value: '0xabc', from: 100, to: 500},
353
+ {value: '0xabc', from: 600, to: undefined},
354
+ ])
355
+ })
356
+
357
+ it('handles delete-then-add at same block', function () {
358
+ let reg = new TemplateRegistry()
359
+ reg.init([
360
+ {type: 'add', key: 'log', value: '0xabc', blockNumber: 100},
361
+ {type: 'delete', key: 'log', value: '0xabc', blockNumber: 500},
362
+ {type: 'add', key: 'log', value: '0xabc', blockNumber: 500},
363
+ ])
364
+ assert.deepStrictEqual(values(reg, 'log'), [
365
+ {value: '0xabc', from: 100, to: 500},
366
+ {value: '0xabc', from: 500, to: undefined},
367
+ ])
368
+ })
369
+
370
+ it('clears previous state', function () {
371
+ let reg = new TemplateRegistry()
372
+ reg.apply({type: 'add', key: 'log', value: '0xabc', blockNumber: 100})
373
+ reg.init([
374
+ {type: 'add', key: 'log', value: '0xdef', blockNumber: 200},
375
+ ])
376
+ assert.deepStrictEqual(values(reg, 'log'), [
377
+ {value: '0xdef', from: 200, to: undefined},
378
+ ])
379
+ })
380
+
381
+ it('clears undo history', function () {
382
+ let reg = new TemplateRegistry()
383
+ reg.apply({type: 'add', key: 'log', value: '0xabc', blockNumber: 100})
384
+ reg.init([
385
+ {type: 'add', key: 'log', value: '0xabc', blockNumber: 100},
386
+ ])
387
+ reg.rollbackTo(-1)
388
+ assert.deepStrictEqual(values(reg, 'log'), [
389
+ {value: '0xabc', from: 100, to: undefined},
390
+ ])
391
+ })
392
+
393
+ it('replays hot block mutations with undo log', function () {
394
+ let reg = new TemplateRegistry()
395
+ reg.init(
396
+ [{type: 'add', key: 'log', value: '0xabc', blockNumber: 100}],
397
+ [
398
+ {blockNumber: 1001, templates: [{type: 'add', key: 'log', value: '0xdef', blockNumber: 200}]},
399
+ {blockNumber: 1002, templates: [{type: 'delete', key: 'log', value: '0xabc', blockNumber: 500}]},
400
+ ]
401
+ )
402
+ assert.deepStrictEqual(values(reg, 'log'), [
403
+ {value: '0xabc', from: 100, to: 500},
404
+ {value: '0xdef', from: 200, to: undefined},
405
+ ])
406
+
407
+ reg.rollbackTo(1001)
408
+ assert.deepStrictEqual(values(reg, 'log'), [
409
+ {value: '0xabc', from: 100, to: undefined},
410
+ {value: '0xdef', from: 200, to: undefined},
411
+ ])
412
+
413
+ reg.rollbackTo(-1)
414
+ assert.deepStrictEqual(values(reg, 'log'), [
415
+ {value: '0xabc', from: 100, to: undefined},
416
+ ])
417
+ })
418
+
419
+ it('hot block rollback fully restores finalized state', function () {
420
+ let reg = new TemplateRegistry()
421
+ reg.init(
422
+ [
423
+ {type: 'add', key: 'log', value: '0xabc', blockNumber: 100},
424
+ {type: 'delete', key: 'log', value: '0xabc', blockNumber: 500},
425
+ ],
426
+ [
427
+ {blockNumber: 1001, templates: [{type: 'add', key: 'log', value: '0xabc', blockNumber: 600}]},
428
+ ]
429
+ )
430
+ assert.deepStrictEqual(values(reg, 'log'), [
431
+ {value: '0xabc', from: 100, to: 500},
432
+ {value: '0xabc', from: 600, to: undefined},
433
+ ])
434
+
435
+ reg.rollbackTo(-1)
436
+ assert.deepStrictEqual(values(reg, 'log'), [
437
+ {value: '0xabc', from: 100, to: 500},
438
+ ])
439
+ })
440
+ })
441
+
442
+ describe('rollbackTo', function () {
443
+ it('undoes changes after given block', async function () {
444
+ let reg = new TemplateRegistry()
445
+ await reg.transact({from: 0, to: 100}, async (t) => {
446
+ t.add('log', '0xabc', 50)
447
+ })
448
+ await reg.transact({from: 101, to: 200}, async (t) => {
449
+ t.add('log', '0xdef', 150)
450
+ })
451
+ reg.rollbackTo(100)
452
+ assert.deepStrictEqual(values(reg, 'log'), [
453
+ {value: '0xabc', from: 50, to: undefined},
454
+ ])
455
+ })
456
+
457
+ it('cleans up empty maps after undo', async function () {
458
+ let reg = new TemplateRegistry()
459
+ await reg.transact({from: 0, to: 100}, async (t) => {
460
+ t.add('log', '0xabc', 50)
461
+ })
462
+ reg.rollbackTo(-1)
463
+ assert.deepStrictEqual(reg.get('log'), [])
464
+ })
465
+
466
+ it('rollback at exact undo entry boundary keeps that entry', async function () {
467
+ let reg = new TemplateRegistry()
468
+ await reg.transact({from: 0, to: 100}, async (t) => {
469
+ t.add('log', '0xabc', 50)
470
+ })
471
+ await reg.transact({from: 101, to: 200}, async (t) => {
472
+ t.add('log', '0xdef', 150)
473
+ })
474
+ reg.rollbackTo(200)
475
+ assert.deepStrictEqual(values(reg, 'log'), [
476
+ {value: '0xabc', from: 50, to: undefined},
477
+ {value: '0xdef', from: 150, to: undefined},
478
+ ])
479
+ })
480
+
481
+ it('rollback beyond all entries is a no-op', async function () {
482
+ let reg = new TemplateRegistry()
483
+ await reg.transact({from: 0, to: 100}, async (t) => {
484
+ t.add('log', '0xabc', 50)
485
+ })
486
+ reg.rollbackTo(500)
487
+ assert.deepStrictEqual(values(reg, 'log'), [
488
+ {value: '0xabc', from: 50, to: undefined},
489
+ ])
490
+ })
491
+ })
492
+
493
+ describe('prune', function () {
494
+ it('is a no-op when target is before all undo entries', async function () {
495
+ let reg = new TemplateRegistry()
496
+ await reg.transact({from: 0, to: 100}, async (t) => {
497
+ t.add('log', '0xabc', 50)
498
+ })
499
+ await reg.transact({from: 101, to: 200}, async (t) => {
500
+ t.add('log', '0xdef', 150)
501
+ })
502
+ reg.prune(-1)
503
+ reg.rollbackTo(-1)
504
+ assert.deepStrictEqual(values(reg, 'log'), [])
505
+ })
506
+
507
+ it('moves undo entries at or below target into base mutations', async function () {
508
+ let reg = new TemplateRegistry()
509
+ await reg.transact({from: 0, to: 100}, async (t) => {
510
+ t.add('log', '0xabc', 50)
511
+ })
512
+ await reg.transact({from: 101, to: 200}, async (t) => {
513
+ t.add('log', '0xdef', 150)
514
+ })
515
+ reg.prune(100)
516
+ reg.rollbackTo(-1)
517
+ assert.deepStrictEqual(values(reg, 'log'), [
518
+ {value: '0xabc', from: 50, to: undefined},
519
+ ])
520
+ })
521
+
522
+ it('moves all undo entries when target is beyond all', async function () {
523
+ let reg = new TemplateRegistry()
524
+ await reg.transact({from: 0, to: 100}, async (t) => {
525
+ t.add('log', '0xabc', 50)
526
+ })
527
+ await reg.transact({from: 101, to: 200}, async (t) => {
528
+ t.add('log', '0xdef', 150)
529
+ })
530
+ reg.prune(500)
531
+ reg.rollbackTo(-1)
532
+ assert.deepStrictEqual(values(reg, 'log'), [
533
+ {value: '0xabc', from: 50, to: undefined},
534
+ {value: '0xdef', from: 150, to: undefined},
535
+ ])
536
+ })
537
+
538
+ it('preserves state after pruning', async function () {
539
+ let reg = new TemplateRegistry()
540
+ await reg.transact({from: 0, to: 100}, async (t) => {
541
+ t.add('log', '0xabc', 50)
542
+ })
543
+ await reg.transact({from: 101, to: 200}, async (t) => {
544
+ t.add('log', '0xdef', 150)
545
+ })
546
+ reg.prune(100)
547
+ assert.deepStrictEqual(values(reg, 'log'), [
548
+ {value: '0xabc', from: 50, to: undefined},
549
+ {value: '0xdef', from: 150, to: undefined},
550
+ ])
551
+ })
552
+
553
+ it('prune then rollback only undoes un-pruned entries', async function () {
554
+ let reg = new TemplateRegistry()
555
+ await reg.transact({from: 0, to: 100}, async (t) => {
556
+ t.add('log', '0xabc', 50)
557
+ })
558
+ await reg.transact({from: 101, to: 200}, async (t) => {
559
+ t.add('log', '0xdef', 150)
560
+ })
561
+ await reg.transact({from: 201, to: 300}, async (t) => {
562
+ t.add('log', '0xghi', 250)
563
+ })
564
+ reg.prune(200)
565
+ reg.rollbackTo(200)
566
+ assert.deepStrictEqual(values(reg, 'log'), [
567
+ {value: '0xabc', from: 50, to: undefined},
568
+ {value: '0xdef', from: 150, to: undefined},
569
+ ])
570
+ })
571
+ })
572
+
573
+ describe('has (via transact)', function () {
574
+ it('sees template added in the same transaction', async function () {
575
+ let reg = new TemplateRegistry()
576
+ let seen = false
577
+ await reg.transact({from: 0, to: 200}, async (t) => {
578
+ t.add('log', '0xabc', 100)
579
+ seen = t.has('log', '0xabc', 150)
580
+ })
581
+ assert.strictEqual(seen, true)
582
+ })
583
+
584
+ it('sees template from a previous transaction', async function () {
585
+ let reg = new TemplateRegistry()
586
+ await reg.transact({from: 0, to: 100}, async (t) => {
587
+ t.add('log', '0xabc', 50)
588
+ })
589
+ let seen = false
590
+ await reg.transact({from: 101, to: 200}, async (t) => {
591
+ seen = t.has('log', '0xabc', 150)
592
+ })
593
+ assert.strictEqual(seen, true)
594
+ })
595
+
596
+ it('does not see template at block before activation', async function () {
597
+ let reg = new TemplateRegistry()
598
+ let seen = true
599
+ await reg.transact({from: 0, to: 200}, async (t) => {
600
+ t.add('log', '0xabc', 100)
601
+ seen = t.has('log', '0xabc', 50)
602
+ })
603
+ assert.strictEqual(seen, false)
604
+ })
605
+
606
+ it('does not see deleted template after deactivation block', async function () {
607
+ let reg = new TemplateRegistry()
608
+ await reg.transact({from: 0, to: 100}, async (t) => {
609
+ t.add('log', '0xabc', 50)
610
+ })
611
+ let seen = true
612
+ await reg.transact({from: 101, to: 600}, async (t) => {
613
+ t.remove('log', '0xabc', 500)
614
+ seen = t.has('log', '0xabc', 501)
615
+ })
616
+ assert.strictEqual(seen, false)
617
+ })
618
+ })
619
+
620
+ describe('edge cases', function () {
621
+ it('transact with no mutations returns changed: false and empty data', async function () {
622
+ let reg = new TemplateRegistry()
623
+ let result = await reg.transact({from: 0, to: 100}, async () => {})
624
+ assert.strictEqual(result.changed, false)
625
+ assert.deepStrictEqual(result.data, [])
626
+ })
627
+
628
+ it('init with empty mutations array clears state', function () {
629
+ let reg = new TemplateRegistry()
630
+ reg.apply({type: 'add', key: 'log', value: '0xabc', blockNumber: 100})
631
+ reg.init([])
632
+ assert.deepStrictEqual(reg.get('log'), [])
633
+ })
634
+
635
+ it('init then transact works on clean state', async function () {
636
+ let reg = new TemplateRegistry()
637
+ reg.apply({type: 'add', key: 'log', value: '0xold', blockNumber: 10})
638
+ reg.init([
639
+ {type: 'add', key: 'log', value: '0xabc', blockNumber: 100},
640
+ ])
641
+ let result = await reg.transact({from: 100, to: 200}, async (t) => {
642
+ t.add('log', '0xdef', 150)
643
+ })
644
+ assert.strictEqual(result.changed, true)
645
+ assert.deepStrictEqual(values(reg, 'log'), [
646
+ {value: '0xabc', from: 100, to: undefined},
647
+ {value: '0xdef', from: 150, to: undefined},
648
+ ])
649
+ })
650
+ })
651
+ })