@aztec/archiver 0.86.0 → 0.87.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/dest/archiver/archiver.d.ts +62 -5
- package/dest/archiver/archiver.d.ts.map +1 -1
- package/dest/archiver/archiver.js +362 -91
- package/dest/archiver/archiver_store.d.ts +33 -17
- package/dest/archiver/archiver_store.d.ts.map +1 -1
- package/dest/archiver/archiver_store_test_suite.d.ts.map +1 -1
- package/dest/archiver/archiver_store_test_suite.js +364 -62
- package/dest/archiver/data_retrieval.d.ts +23 -14
- package/dest/archiver/data_retrieval.d.ts.map +1 -1
- package/dest/archiver/data_retrieval.js +86 -38
- package/dest/archiver/errors.d.ts +8 -0
- package/dest/archiver/errors.d.ts.map +1 -1
- package/dest/archiver/errors.js +12 -0
- package/dest/archiver/instrumentation.d.ts.map +1 -1
- package/dest/archiver/kv_archiver_store/block_store.d.ts +4 -1
- package/dest/archiver/kv_archiver_store/block_store.d.ts.map +1 -1
- package/dest/archiver/kv_archiver_store/block_store.js +43 -6
- package/dest/archiver/kv_archiver_store/contract_instance_store.d.ts +3 -1
- package/dest/archiver/kv_archiver_store/contract_instance_store.d.ts.map +1 -1
- package/dest/archiver/kv_archiver_store/contract_instance_store.js +17 -3
- package/dest/archiver/kv_archiver_store/kv_archiver_store.d.ts +24 -14
- package/dest/archiver/kv_archiver_store/kv_archiver_store.d.ts.map +1 -1
- package/dest/archiver/kv_archiver_store/kv_archiver_store.js +37 -11
- package/dest/archiver/kv_archiver_store/log_store.d.ts.map +1 -1
- package/dest/archiver/kv_archiver_store/log_store.js +1 -1
- package/dest/archiver/kv_archiver_store/message_store.d.ts +21 -15
- package/dest/archiver/kv_archiver_store/message_store.d.ts.map +1 -1
- package/dest/archiver/kv_archiver_store/message_store.js +150 -48
- package/dest/archiver/structs/inbox_message.d.ts +14 -0
- package/dest/archiver/structs/inbox_message.d.ts.map +1 -0
- package/dest/archiver/structs/inbox_message.js +38 -0
- package/dest/rpc/index.d.ts +1 -1
- package/dest/test/mock_l2_block_source.d.ts +2 -0
- package/dest/test/mock_l2_block_source.d.ts.map +1 -1
- package/dest/test/mock_l2_block_source.js +8 -1
- package/dest/test/mock_structs.d.ts +9 -0
- package/dest/test/mock_structs.d.ts.map +1 -0
- package/dest/test/mock_structs.js +37 -0
- package/package.json +15 -15
- package/src/archiver/archiver.ts +431 -108
- package/src/archiver/archiver_store.ts +37 -18
- package/src/archiver/archiver_store_test_suite.ts +307 -52
- package/src/archiver/data_retrieval.ts +130 -53
- package/src/archiver/errors.ts +21 -0
- package/src/archiver/instrumentation.ts +4 -1
- package/src/archiver/kv_archiver_store/block_store.ts +46 -8
- package/src/archiver/kv_archiver_store/contract_instance_store.ts +20 -7
- package/src/archiver/kv_archiver_store/kv_archiver_store.ts +61 -17
- package/src/archiver/kv_archiver_store/log_store.ts +6 -2
- package/src/archiver/kv_archiver_store/message_store.ts +209 -53
- package/src/archiver/structs/inbox_message.ts +40 -0
- package/src/test/mock_l2_block_source.ts +9 -1
- package/src/test/mock_structs.ts +49 -0
- package/dest/archiver/memory_archiver_store/l1_to_l2_message_store.d.ts +0 -23
- package/dest/archiver/memory_archiver_store/l1_to_l2_message_store.d.ts.map +0 -1
- package/dest/archiver/memory_archiver_store/l1_to_l2_message_store.js +0 -49
- package/src/archiver/memory_archiver_store/l1_to_l2_message_store.ts +0 -61
|
@@ -1,8 +1,11 @@
|
|
|
1
|
-
import { INITIAL_L2_BLOCK_NUM,
|
|
1
|
+
import { INITIAL_L2_BLOCK_NUM, NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP, PRIVATE_LOG_SIZE_IN_FIELDS, PUBLIC_LOG_SIZE_IN_FIELDS } from '@aztec/constants';
|
|
2
|
+
import { makeTuple } from '@aztec/foundation/array';
|
|
3
|
+
import { Buffer16, Buffer32 } from '@aztec/foundation/buffer';
|
|
2
4
|
import { times, timesParallel } from '@aztec/foundation/collection';
|
|
3
5
|
import { randomInt } from '@aztec/foundation/crypto';
|
|
4
6
|
import { Signature } from '@aztec/foundation/eth-signature';
|
|
5
7
|
import { Fr } from '@aztec/foundation/fields';
|
|
8
|
+
import { toArray } from '@aztec/foundation/iterable';
|
|
6
9
|
import { sleep } from '@aztec/foundation/sleep';
|
|
7
10
|
import { AztecAddress } from '@aztec/stdlib/aztec-address';
|
|
8
11
|
import { L2Block, wrapInBlock } from '@aztec/stdlib/block';
|
|
@@ -12,6 +15,9 @@ import { InboxLeaf } from '@aztec/stdlib/messaging';
|
|
|
12
15
|
import { makeContractClassPublic, makeExecutablePrivateFunctionWithMembershipProof, makeUtilityFunctionWithMembershipProof } from '@aztec/stdlib/testing';
|
|
13
16
|
import '@aztec/stdlib/testing/jest';
|
|
14
17
|
import { TxEffect, TxHash } from '@aztec/stdlib/tx';
|
|
18
|
+
import { makeInboxMessage, makeInboxMessages } from '../test/mock_structs.js';
|
|
19
|
+
import { BlockNumberNotSequentialError, InitialBlockNumberNotSequentialError } from './errors.js';
|
|
20
|
+
import { MessageStoreError } from './kv_archiver_store/message_store.js';
|
|
15
21
|
/**
|
|
16
22
|
* @param testName - The name of the test suite.
|
|
17
23
|
* @param getStore - Returns an instance of a store that's already been initialized.
|
|
@@ -77,17 +83,32 @@ import { TxEffect, TxHash } from '@aztec/stdlib/tx';
|
|
|
77
83
|
await store.addBlocks(blocks);
|
|
78
84
|
await expect(store.addBlocks(blocks)).resolves.toBe(true);
|
|
79
85
|
});
|
|
86
|
+
it('throws an error if the previous block does not exist in the store', async ()=>{
|
|
87
|
+
const block = makePublished(await L2Block.random(2), 2);
|
|
88
|
+
await expect(store.addBlocks([
|
|
89
|
+
block
|
|
90
|
+
])).rejects.toThrow(InitialBlockNumberNotSequentialError);
|
|
91
|
+
await expect(store.getPublishedBlocks(1, 10)).resolves.toEqual([]);
|
|
92
|
+
});
|
|
93
|
+
it('throws an error if there is a gap in the blocks being added', async ()=>{
|
|
94
|
+
const blocks = [
|
|
95
|
+
makePublished(await L2Block.random(1), 1),
|
|
96
|
+
makePublished(await L2Block.random(3), 3)
|
|
97
|
+
];
|
|
98
|
+
await expect(store.addBlocks(blocks)).rejects.toThrow(BlockNumberNotSequentialError);
|
|
99
|
+
await expect(store.getPublishedBlocks(1, 10)).resolves.toEqual([]);
|
|
100
|
+
});
|
|
80
101
|
});
|
|
81
102
|
describe('unwindBlocks', ()=>{
|
|
82
103
|
it('unwinding blocks will remove blocks from the chain', async ()=>{
|
|
83
104
|
await store.addBlocks(blocks);
|
|
84
105
|
const blockNumber = await store.getSynchedL2BlockNumber();
|
|
85
|
-
expectBlocksEqual(await store.
|
|
106
|
+
expectBlocksEqual(await store.getPublishedBlocks(blockNumber, 1), [
|
|
86
107
|
blocks[blocks.length - 1]
|
|
87
108
|
]);
|
|
88
109
|
await store.unwindBlocks(blockNumber, 1);
|
|
89
110
|
expect(await store.getSynchedL2BlockNumber()).toBe(blockNumber - 1);
|
|
90
|
-
expect(await store.
|
|
111
|
+
expect(await store.getPublishedBlocks(blockNumber, 1)).toEqual([]);
|
|
91
112
|
});
|
|
92
113
|
it('can unwind multiple empty blocks', async ()=>{
|
|
93
114
|
const emptyBlocks = await timesParallel(10, async (i)=>makePublished(await L2Block.random(i + 1, 0), i + 10));
|
|
@@ -95,7 +116,7 @@ import { TxEffect, TxHash } from '@aztec/stdlib/tx';
|
|
|
95
116
|
expect(await store.getSynchedL2BlockNumber()).toBe(10);
|
|
96
117
|
await store.unwindBlocks(10, 3);
|
|
97
118
|
expect(await store.getSynchedL2BlockNumber()).toBe(7);
|
|
98
|
-
expect((await store.
|
|
119
|
+
expect((await store.getPublishedBlocks(1, 10)).map((b)=>b.block.number)).toEqual([
|
|
99
120
|
1,
|
|
100
121
|
2,
|
|
101
122
|
3,
|
|
@@ -115,16 +136,33 @@ import { TxEffect, TxHash } from '@aztec/stdlib/tx';
|
|
|
115
136
|
await store.addBlocks(blocks);
|
|
116
137
|
});
|
|
117
138
|
it.each(blockTests)('retrieves previously stored blocks', async (start, limit, getExpectedBlocks)=>{
|
|
118
|
-
expectBlocksEqual(await store.
|
|
139
|
+
expectBlocksEqual(await store.getPublishedBlocks(start, limit), getExpectedBlocks());
|
|
119
140
|
});
|
|
120
141
|
it('returns an empty array if no blocks are found', async ()=>{
|
|
121
|
-
await expect(store.
|
|
142
|
+
await expect(store.getPublishedBlocks(12, 1)).resolves.toEqual([]);
|
|
122
143
|
});
|
|
123
144
|
it('throws an error if limit is invalid', async ()=>{
|
|
124
|
-
await expect(store.
|
|
145
|
+
await expect(store.getPublishedBlocks(1, 0)).rejects.toThrow('Invalid limit: 0');
|
|
125
146
|
});
|
|
126
147
|
it('throws an error if `from` it is out of range', async ()=>{
|
|
127
|
-
await expect(store.
|
|
148
|
+
await expect(store.getPublishedBlocks(INITIAL_L2_BLOCK_NUM - 100, 1)).rejects.toThrow('Invalid start: -99');
|
|
149
|
+
});
|
|
150
|
+
it('throws an error if unexpected initial block number is found', async ()=>{
|
|
151
|
+
await store.addBlocks([
|
|
152
|
+
makePublished(await L2Block.random(21), 31)
|
|
153
|
+
], {
|
|
154
|
+
force: true
|
|
155
|
+
});
|
|
156
|
+
await expect(store.getPublishedBlocks(20, 1)).rejects.toThrow(`mismatch`);
|
|
157
|
+
});
|
|
158
|
+
it('throws an error if a gap is found', async ()=>{
|
|
159
|
+
await store.addBlocks([
|
|
160
|
+
makePublished(await L2Block.random(20), 30),
|
|
161
|
+
makePublished(await L2Block.random(22), 32)
|
|
162
|
+
], {
|
|
163
|
+
force: true
|
|
164
|
+
});
|
|
165
|
+
await expect(store.getPublishedBlocks(20, 2)).rejects.toThrow(`mismatch`);
|
|
128
166
|
});
|
|
129
167
|
});
|
|
130
168
|
describe('getSyncedL2BlockNumber', ()=>{
|
|
@@ -151,15 +189,46 @@ import { TxEffect, TxHash } from '@aztec/stdlib/tx';
|
|
|
151
189
|
});
|
|
152
190
|
});
|
|
153
191
|
it('returns the L1 block number that most recently added messages from inbox', async ()=>{
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
192
|
+
const l1BlockHash = Buffer32.random();
|
|
193
|
+
const l1BlockNumber = 10n;
|
|
194
|
+
await store.setMessageSynchedL1Block({
|
|
195
|
+
l1BlockNumber: 5n,
|
|
196
|
+
l1BlockHash: Buffer32.random()
|
|
197
|
+
});
|
|
198
|
+
await store.addL1ToL2Messages([
|
|
199
|
+
makeInboxMessage(Buffer16.ZERO, {
|
|
200
|
+
l1BlockNumber,
|
|
201
|
+
l1BlockHash
|
|
202
|
+
})
|
|
203
|
+
]);
|
|
204
|
+
await expect(store.getSynchPoint()).resolves.toEqual({
|
|
205
|
+
blocksSynchedTo: undefined,
|
|
206
|
+
messagesSynchedTo: {
|
|
207
|
+
l1BlockHash,
|
|
208
|
+
l1BlockNumber
|
|
209
|
+
}
|
|
210
|
+
});
|
|
211
|
+
});
|
|
212
|
+
it('returns the latest syncpoint if latest message is behind', async ()=>{
|
|
213
|
+
const l1BlockHash = Buffer32.random();
|
|
214
|
+
const l1BlockNumber = 10n;
|
|
215
|
+
await store.setMessageSynchedL1Block({
|
|
216
|
+
l1BlockNumber,
|
|
217
|
+
l1BlockHash
|
|
218
|
+
});
|
|
219
|
+
const msg = makeInboxMessage(Buffer16.ZERO, {
|
|
220
|
+
l1BlockNumber: 5n,
|
|
221
|
+
l1BlockHash: Buffer32.random()
|
|
159
222
|
});
|
|
223
|
+
await store.addL1ToL2Messages([
|
|
224
|
+
msg
|
|
225
|
+
]);
|
|
160
226
|
await expect(store.getSynchPoint()).resolves.toEqual({
|
|
161
227
|
blocksSynchedTo: undefined,
|
|
162
|
-
messagesSynchedTo:
|
|
228
|
+
messagesSynchedTo: {
|
|
229
|
+
l1BlockHash,
|
|
230
|
+
l1BlockNumber
|
|
231
|
+
}
|
|
163
232
|
});
|
|
164
233
|
});
|
|
165
234
|
});
|
|
@@ -282,35 +351,224 @@ import { TxEffect, TxHash } from '@aztec/stdlib/tx';
|
|
|
282
351
|
});
|
|
283
352
|
});
|
|
284
353
|
describe('L1 to L2 Messages', ()=>{
|
|
285
|
-
const
|
|
286
|
-
const
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
await store.addL1ToL2Messages(
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
354
|
+
const initialL2BlockNumber = 13n;
|
|
355
|
+
const checkMessages = async (msgs)=>{
|
|
356
|
+
expect(await store.getLastL1ToL2Message()).toEqual(msgs.at(-1));
|
|
357
|
+
expect(await toArray(store.iterateL1ToL2Messages())).toEqual(msgs);
|
|
358
|
+
expect(await store.getTotalL1ToL2MessageCount()).toEqual(BigInt(msgs.length));
|
|
359
|
+
};
|
|
360
|
+
const makeInboxMessagesWithFullBlocks = (blockCount, opts = {})=>makeInboxMessages(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP * blockCount, {
|
|
361
|
+
overrideFn: (msg, i)=>{
|
|
362
|
+
const l2BlockNumber = (opts.initialL2BlockNumber ?? initialL2BlockNumber) + BigInt(Math.floor(i / NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP));
|
|
363
|
+
const index = InboxLeaf.smallestIndexFromL2Block(l2BlockNumber) + BigInt(i % NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP);
|
|
364
|
+
return {
|
|
365
|
+
...msg,
|
|
366
|
+
l2BlockNumber,
|
|
367
|
+
index
|
|
368
|
+
};
|
|
369
|
+
}
|
|
370
|
+
});
|
|
371
|
+
it('stores first message ever', async ()=>{
|
|
372
|
+
const msg = makeInboxMessage(Buffer16.ZERO, {
|
|
373
|
+
index: 0n,
|
|
374
|
+
l2BlockNumber: 1n
|
|
375
|
+
});
|
|
376
|
+
await store.addL1ToL2Messages([
|
|
377
|
+
msg
|
|
378
|
+
]);
|
|
379
|
+
await checkMessages([
|
|
380
|
+
msg
|
|
381
|
+
]);
|
|
382
|
+
expect(await store.getL1ToL2Messages(1n)).toEqual([
|
|
383
|
+
msg.leaf
|
|
384
|
+
]);
|
|
385
|
+
});
|
|
386
|
+
it('stores single message', async ()=>{
|
|
387
|
+
const msg = makeInboxMessage(Buffer16.ZERO, {
|
|
388
|
+
l2BlockNumber: 2n
|
|
389
|
+
});
|
|
390
|
+
await store.addL1ToL2Messages([
|
|
391
|
+
msg
|
|
392
|
+
]);
|
|
393
|
+
await checkMessages([
|
|
394
|
+
msg
|
|
395
|
+
]);
|
|
396
|
+
expect(await store.getL1ToL2Messages(2n)).toEqual([
|
|
397
|
+
msg.leaf
|
|
398
|
+
]);
|
|
399
|
+
});
|
|
400
|
+
it('stores and returns messages across different blocks', async ()=>{
|
|
401
|
+
const msgs = makeInboxMessages(5, {
|
|
402
|
+
initialL2BlockNumber
|
|
403
|
+
});
|
|
404
|
+
await store.addL1ToL2Messages(msgs);
|
|
405
|
+
await checkMessages(msgs);
|
|
406
|
+
expect(await store.getL1ToL2Messages(initialL2BlockNumber + 2n)).toEqual([
|
|
407
|
+
msgs[2]
|
|
408
|
+
].map((m)=>m.leaf));
|
|
409
|
+
});
|
|
410
|
+
it('stores the same messages again', async ()=>{
|
|
411
|
+
const msgs = makeInboxMessages(5, {
|
|
412
|
+
initialL2BlockNumber
|
|
413
|
+
});
|
|
414
|
+
await store.addL1ToL2Messages(msgs);
|
|
415
|
+
await store.addL1ToL2Messages(msgs.slice(2));
|
|
416
|
+
await checkMessages(msgs);
|
|
417
|
+
});
|
|
418
|
+
it('stores and returns messages across different blocks with gaps', async ()=>{
|
|
419
|
+
const msgs1 = makeInboxMessages(3, {
|
|
420
|
+
initialL2BlockNumber: 1n
|
|
421
|
+
});
|
|
422
|
+
const msgs2 = makeInboxMessages(3, {
|
|
423
|
+
initialL2BlockNumber: 20n,
|
|
424
|
+
initialHash: msgs1.at(-1).rollingHash
|
|
425
|
+
});
|
|
426
|
+
await store.addL1ToL2Messages(msgs1);
|
|
427
|
+
await store.addL1ToL2Messages(msgs2);
|
|
428
|
+
await checkMessages([
|
|
429
|
+
...msgs1,
|
|
430
|
+
...msgs2
|
|
431
|
+
]);
|
|
432
|
+
expect(await store.getL1ToL2Messages(1n)).toEqual([
|
|
433
|
+
msgs1[0].leaf
|
|
434
|
+
]);
|
|
435
|
+
expect(await store.getL1ToL2Messages(4n)).toEqual([]);
|
|
436
|
+
expect(await store.getL1ToL2Messages(20n)).toEqual([
|
|
437
|
+
msgs2[0].leaf
|
|
438
|
+
]);
|
|
439
|
+
expect(await store.getL1ToL2Messages(24n)).toEqual([]);
|
|
440
|
+
});
|
|
441
|
+
it('stores and returns messages with block numbers larger than a byte', async ()=>{
|
|
442
|
+
const msgs = makeInboxMessages(5, {
|
|
443
|
+
initialL2BlockNumber: 1000n
|
|
444
|
+
});
|
|
445
|
+
await store.addL1ToL2Messages(msgs);
|
|
446
|
+
await checkMessages(msgs);
|
|
447
|
+
expect(await store.getL1ToL2Messages(1002n)).toEqual([
|
|
448
|
+
msgs[2]
|
|
449
|
+
].map((m)=>m.leaf));
|
|
450
|
+
});
|
|
451
|
+
it('stores and returns multiple messages per block', async ()=>{
|
|
452
|
+
const msgs = makeInboxMessagesWithFullBlocks(4);
|
|
453
|
+
await store.addL1ToL2Messages(msgs);
|
|
454
|
+
await checkMessages(msgs);
|
|
455
|
+
const blockMessages = await store.getL1ToL2Messages(initialL2BlockNumber + 1n);
|
|
456
|
+
expect(blockMessages).toHaveLength(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP);
|
|
457
|
+
expect(blockMessages).toEqual(msgs.slice(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP, NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP * 2).map((m)=>m.leaf));
|
|
458
|
+
});
|
|
459
|
+
it('stores messages in multiple operations', async ()=>{
|
|
460
|
+
const msgs = makeInboxMessages(20, {
|
|
461
|
+
initialL2BlockNumber
|
|
462
|
+
});
|
|
463
|
+
await store.addL1ToL2Messages(msgs.slice(0, 10));
|
|
464
|
+
await store.addL1ToL2Messages(msgs.slice(10, 20));
|
|
465
|
+
expect(await store.getL1ToL2Messages(initialL2BlockNumber + 2n)).toEqual([
|
|
466
|
+
msgs[2]
|
|
467
|
+
].map((m)=>m.leaf));
|
|
468
|
+
expect(await store.getL1ToL2Messages(initialL2BlockNumber + 12n)).toEqual([
|
|
469
|
+
msgs[12]
|
|
470
|
+
].map((m)=>m.leaf));
|
|
471
|
+
await checkMessages(msgs);
|
|
472
|
+
});
|
|
473
|
+
it('iterates over messages from start index', async ()=>{
|
|
474
|
+
const msgs = makeInboxMessages(10, {
|
|
475
|
+
initialL2BlockNumber
|
|
476
|
+
});
|
|
477
|
+
await store.addL1ToL2Messages(msgs);
|
|
478
|
+
const iterated = await toArray(store.iterateL1ToL2Messages({
|
|
479
|
+
start: msgs[3].index
|
|
480
|
+
}));
|
|
481
|
+
expect(iterated).toEqual(msgs.slice(3));
|
|
482
|
+
});
|
|
483
|
+
it('iterates over messages in reverse', async ()=>{
|
|
484
|
+
const msgs = makeInboxMessages(10, {
|
|
485
|
+
initialL2BlockNumber
|
|
486
|
+
});
|
|
487
|
+
await store.addL1ToL2Messages(msgs);
|
|
488
|
+
const iterated = await toArray(store.iterateL1ToL2Messages({
|
|
489
|
+
reverse: true,
|
|
490
|
+
end: msgs[3].index
|
|
491
|
+
}));
|
|
492
|
+
expect(iterated).toEqual(msgs.slice(0, 4).reverse());
|
|
493
|
+
});
|
|
494
|
+
it('throws if messages are added out of order', async ()=>{
|
|
495
|
+
const msgs = makeInboxMessages(5, {
|
|
496
|
+
overrideFn: (msg, i)=>({
|
|
497
|
+
...msg,
|
|
498
|
+
index: BigInt(10 - i)
|
|
499
|
+
})
|
|
500
|
+
});
|
|
501
|
+
await expect(store.addL1ToL2Messages(msgs)).rejects.toThrow(MessageStoreError);
|
|
502
|
+
});
|
|
503
|
+
it('throws if block number for the first message is out of order', async ()=>{
|
|
504
|
+
const msgs = makeInboxMessages(4, {
|
|
505
|
+
initialL2BlockNumber
|
|
506
|
+
});
|
|
507
|
+
msgs[2].l2BlockNumber = initialL2BlockNumber - 1n;
|
|
508
|
+
await store.addL1ToL2Messages(msgs.slice(0, 2));
|
|
509
|
+
await expect(store.addL1ToL2Messages(msgs.slice(2, 4))).rejects.toThrow(MessageStoreError);
|
|
510
|
+
});
|
|
511
|
+
it('throws if rolling hash is not correct', async ()=>{
|
|
512
|
+
const msgs = makeInboxMessages(5);
|
|
513
|
+
msgs[1].rollingHash = Buffer16.random();
|
|
514
|
+
await expect(store.addL1ToL2Messages(msgs)).rejects.toThrow(MessageStoreError);
|
|
515
|
+
});
|
|
516
|
+
it('throws if rolling hash for first message is not correct', async ()=>{
|
|
517
|
+
const msgs = makeInboxMessages(4);
|
|
518
|
+
msgs[2].rollingHash = Buffer16.random();
|
|
519
|
+
await store.addL1ToL2Messages(msgs.slice(0, 2));
|
|
520
|
+
await expect(store.addL1ToL2Messages(msgs.slice(2, 4))).rejects.toThrow(MessageStoreError);
|
|
521
|
+
});
|
|
522
|
+
it('throws if index is not in the correct range', async ()=>{
|
|
523
|
+
const msgs = makeInboxMessages(5, {
|
|
524
|
+
initialL2BlockNumber
|
|
525
|
+
});
|
|
526
|
+
msgs.at(-1).index += 100n;
|
|
527
|
+
await expect(store.addL1ToL2Messages(msgs)).rejects.toThrow(MessageStoreError);
|
|
528
|
+
});
|
|
529
|
+
it('throws if first index in block has gaps', async ()=>{
|
|
530
|
+
const msgs = makeInboxMessages(4, {
|
|
531
|
+
initialL2BlockNumber
|
|
532
|
+
});
|
|
533
|
+
msgs[2].index++;
|
|
534
|
+
await expect(store.addL1ToL2Messages(msgs)).rejects.toThrow(MessageStoreError);
|
|
535
|
+
});
|
|
536
|
+
it('throws if index does not follow previous one', async ()=>{
|
|
537
|
+
const msgs = makeInboxMessages(2, {
|
|
538
|
+
initialL2BlockNumber,
|
|
539
|
+
overrideFn: (msg, i)=>({
|
|
540
|
+
...msg,
|
|
541
|
+
l2BlockNumber: 2n,
|
|
542
|
+
index: BigInt(i + NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP * 2)
|
|
543
|
+
})
|
|
544
|
+
});
|
|
545
|
+
msgs[1].index++;
|
|
546
|
+
await expect(store.addL1ToL2Messages(msgs)).rejects.toThrow(MessageStoreError);
|
|
547
|
+
});
|
|
548
|
+
it('removes messages up to the given block number', async ()=>{
|
|
549
|
+
const msgs = makeInboxMessagesWithFullBlocks(4, {
|
|
550
|
+
initialL2BlockNumber: 1n
|
|
551
|
+
});
|
|
552
|
+
await store.addL1ToL2Messages(msgs);
|
|
553
|
+
await checkMessages(msgs);
|
|
554
|
+
expect(await store.getL1ToL2Messages(1n)).toHaveLength(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP);
|
|
555
|
+
expect(await store.getL1ToL2Messages(2n)).toHaveLength(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP);
|
|
556
|
+
expect(await store.getL1ToL2Messages(3n)).toHaveLength(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP);
|
|
557
|
+
expect(await store.getL1ToL2Messages(4n)).toHaveLength(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP);
|
|
558
|
+
await store.rollbackL1ToL2MessagesToL2Block(2n);
|
|
559
|
+
expect(await store.getL1ToL2Messages(1n)).toHaveLength(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP);
|
|
560
|
+
expect(await store.getL1ToL2Messages(2n)).toHaveLength(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP);
|
|
561
|
+
expect(await store.getL1ToL2Messages(3n)).toHaveLength(0);
|
|
562
|
+
expect(await store.getL1ToL2Messages(4n)).toHaveLength(0);
|
|
563
|
+
await checkMessages(msgs.slice(0, NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP * 2));
|
|
564
|
+
});
|
|
565
|
+
it('removes messages starting with the given index', async ()=>{
|
|
566
|
+
const msgs = makeInboxMessagesWithFullBlocks(4, {
|
|
567
|
+
initialL2BlockNumber: 1n
|
|
568
|
+
});
|
|
569
|
+
await store.addL1ToL2Messages(msgs);
|
|
570
|
+
await store.removeL1ToL2Messages(msgs[13].index);
|
|
571
|
+
await checkMessages(msgs.slice(0, 13));
|
|
314
572
|
});
|
|
315
573
|
});
|
|
316
574
|
describe('contractInstances', ()=>{
|
|
@@ -386,6 +644,49 @@ import { TxEffect, TxHash } from '@aztec/stdlib/tx';
|
|
|
386
644
|
expect(fetchedInstance?.originalContractClassId).toEqual(classId);
|
|
387
645
|
expect(fetchedInstance?.currentContractClassId).toEqual(nextClassId);
|
|
388
646
|
});
|
|
647
|
+
it('ignores updates for the wrong contract', async ()=>{
|
|
648
|
+
const otherClassId = Fr.random();
|
|
649
|
+
const randomInstance = await SerializableContractInstance.random({
|
|
650
|
+
currentContractClassId: otherClassId,
|
|
651
|
+
originalContractClassId: otherClassId
|
|
652
|
+
});
|
|
653
|
+
const otherContractInstance = {
|
|
654
|
+
...randomInstance,
|
|
655
|
+
address: await AztecAddress.random()
|
|
656
|
+
};
|
|
657
|
+
await store.addContractInstances([
|
|
658
|
+
otherContractInstance
|
|
659
|
+
], 1);
|
|
660
|
+
const fetchedInstance = await store.getContractInstance(otherContractInstance.address, blockOfChange + 1);
|
|
661
|
+
expect(fetchedInstance?.originalContractClassId).toEqual(otherClassId);
|
|
662
|
+
expect(fetchedInstance?.currentContractClassId).toEqual(otherClassId);
|
|
663
|
+
});
|
|
664
|
+
it('bounds its search to the right contract if more than than one update exists', async ()=>{
|
|
665
|
+
const otherClassId = Fr.random();
|
|
666
|
+
const otherNextClassId = Fr.random();
|
|
667
|
+
const randomInstance = await SerializableContractInstance.random({
|
|
668
|
+
currentContractClassId: otherClassId,
|
|
669
|
+
originalContractClassId: otherNextClassId
|
|
670
|
+
});
|
|
671
|
+
const otherContractInstance = {
|
|
672
|
+
...randomInstance,
|
|
673
|
+
address: await AztecAddress.random()
|
|
674
|
+
};
|
|
675
|
+
await store.addContractInstances([
|
|
676
|
+
otherContractInstance
|
|
677
|
+
], 1);
|
|
678
|
+
await store.addContractInstanceUpdates([
|
|
679
|
+
{
|
|
680
|
+
prevContractClassId: otherClassId,
|
|
681
|
+
newContractClassId: otherNextClassId,
|
|
682
|
+
blockOfChange,
|
|
683
|
+
address: otherContractInstance.address
|
|
684
|
+
}
|
|
685
|
+
], blockOfChange - 1);
|
|
686
|
+
const fetchedInstance = await store.getContractInstance(contractInstance.address, blockOfChange + 1);
|
|
687
|
+
expect(fetchedInstance?.originalContractClassId).toEqual(classId);
|
|
688
|
+
expect(fetchedInstance?.currentContractClassId).toEqual(nextClassId);
|
|
689
|
+
});
|
|
389
690
|
});
|
|
390
691
|
describe('contractClasses', ()=>{
|
|
391
692
|
let contractClass;
|
|
@@ -454,16 +755,17 @@ import { TxEffect, TxHash } from '@aztec/stdlib/tx';
|
|
|
454
755
|
const numPrivateLogsPerTx = 3;
|
|
455
756
|
const numPublicLogsPerTx = 2;
|
|
456
757
|
let blocks;
|
|
457
|
-
const makeTag = (blockNumber, txIndex, logIndex, isPublic = false)=>
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
758
|
+
const makeTag = (blockNumber, txIndex, logIndex, isPublic = false)=>blockNumber === 1 && txIndex === 0 && logIndex === 0 ? Fr.ZERO // Shared tag
|
|
759
|
+
: new Fr((blockNumber * 100 + txIndex * 10 + logIndex) * (isPublic ? 123 : 1));
|
|
760
|
+
const makePrivateLog = (tag)=>PrivateLog.from({
|
|
761
|
+
fields: makeTuple(PRIVATE_LOG_SIZE_IN_FIELDS, (i)=>!i ? tag : new Fr(tag.toNumber() + i)),
|
|
762
|
+
emittedLength: PRIVATE_LOG_SIZE_IN_FIELDS
|
|
763
|
+
});
|
|
764
|
+
const makePublicLog = (tag)=>PublicLog.from({
|
|
765
|
+
contractAddress: AztecAddress.fromNumber(1),
|
|
766
|
+
fields: makeTuple(PUBLIC_LOG_SIZE_IN_FIELDS, (i)=>!i ? tag : new Fr(tag.toNumber() + i)),
|
|
767
|
+
emittedLength: PUBLIC_LOG_SIZE_IN_FIELDS
|
|
768
|
+
});
|
|
467
769
|
const mockPrivateLogs = (blockNumber, txIndex)=>{
|
|
468
770
|
return times(numPrivateLogsPerTx, (logIndex)=>{
|
|
469
771
|
const tag = makeTag(blockNumber, txIndex, logIndex);
|
|
@@ -496,27 +798,27 @@ import { TxEffect, TxHash } from '@aztec/stdlib/tx';
|
|
|
496
798
|
};
|
|
497
799
|
};
|
|
498
800
|
beforeEach(async ()=>{
|
|
499
|
-
blocks = await timesParallel(numBlocks, (index)=>mockBlockWithLogs(index));
|
|
801
|
+
blocks = await timesParallel(numBlocks, (index)=>mockBlockWithLogs(index + 1));
|
|
500
802
|
await store.addBlocks(blocks);
|
|
501
803
|
await store.addLogs(blocks.map((b)=>b.block));
|
|
502
804
|
});
|
|
503
805
|
it('is possible to batch request private logs via tags', async ()=>{
|
|
504
806
|
const tags = [
|
|
505
|
-
makeTag(
|
|
506
|
-
makeTag(
|
|
807
|
+
makeTag(2, 1, 2),
|
|
808
|
+
makeTag(1, 2, 0)
|
|
507
809
|
];
|
|
508
810
|
const logsByTags = await store.getLogsByTags(tags);
|
|
509
811
|
expect(logsByTags).toEqual([
|
|
510
812
|
[
|
|
511
813
|
expect.objectContaining({
|
|
512
|
-
blockNumber:
|
|
814
|
+
blockNumber: 2,
|
|
513
815
|
log: makePrivateLog(tags[0]),
|
|
514
816
|
isFromPublic: false
|
|
515
817
|
})
|
|
516
818
|
],
|
|
517
819
|
[
|
|
518
820
|
expect.objectContaining({
|
|
519
|
-
blockNumber:
|
|
821
|
+
blockNumber: 1,
|
|
520
822
|
log: makePrivateLog(tags[1]),
|
|
521
823
|
isFromPublic: false
|
|
522
824
|
})
|
|
@@ -524,20 +826,20 @@ import { TxEffect, TxHash } from '@aztec/stdlib/tx';
|
|
|
524
826
|
]);
|
|
525
827
|
});
|
|
526
828
|
it('is possible to batch request all logs (private and public) via tags', async ()=>{
|
|
527
|
-
// Tag(
|
|
829
|
+
// Tag(1, 0, 0) is shared with the first private log and the first public log.
|
|
528
830
|
const tags = [
|
|
529
|
-
makeTag(
|
|
831
|
+
makeTag(1, 0, 0)
|
|
530
832
|
];
|
|
531
833
|
const logsByTags = await store.getLogsByTags(tags);
|
|
532
834
|
expect(logsByTags).toEqual([
|
|
533
835
|
[
|
|
534
836
|
expect.objectContaining({
|
|
535
|
-
blockNumber:
|
|
837
|
+
blockNumber: 1,
|
|
536
838
|
log: makePrivateLog(tags[0]),
|
|
537
839
|
isFromPublic: false
|
|
538
840
|
}),
|
|
539
841
|
expect.objectContaining({
|
|
540
|
-
blockNumber:
|
|
842
|
+
blockNumber: 1,
|
|
541
843
|
log: makePublicLog(tags[0]),
|
|
542
844
|
isFromPublic: true
|
|
543
845
|
})
|
|
@@ -1,14 +1,29 @@
|
|
|
1
1
|
import type { BlobSinkClientInterface } from '@aztec/blob-sink/client';
|
|
2
|
-
import type { ViemPublicClient } from '@aztec/ethereum';
|
|
2
|
+
import type { ViemClient, ViemPublicClient } from '@aztec/ethereum';
|
|
3
3
|
import type { EthAddress } from '@aztec/foundation/eth-address';
|
|
4
|
+
import { Signature } from '@aztec/foundation/eth-signature';
|
|
4
5
|
import { Fr } from '@aztec/foundation/fields';
|
|
5
6
|
import { type Logger } from '@aztec/foundation/log';
|
|
6
7
|
import { type InboxAbi, RollupAbi } from '@aztec/l1-artifacts';
|
|
7
|
-
import {
|
|
8
|
+
import { Body } from '@aztec/stdlib/block';
|
|
8
9
|
import { Proof } from '@aztec/stdlib/proofs';
|
|
9
|
-
import {
|
|
10
|
+
import { ProposedBlockHeader, StateReference } from '@aztec/stdlib/tx';
|
|
11
|
+
import { type GetContractReturnType, type Hex } from 'viem';
|
|
10
12
|
import type { DataRetrieval } from './structs/data_retrieval.js';
|
|
11
|
-
import type {
|
|
13
|
+
import type { InboxMessage } from './structs/inbox_message.js';
|
|
14
|
+
import type { L1PublishedData, PublishedL2Block } from './structs/published.js';
|
|
15
|
+
export type RetrievedL2Block = {
|
|
16
|
+
l2BlockNumber: bigint;
|
|
17
|
+
archiveRoot: Fr;
|
|
18
|
+
stateReference: StateReference;
|
|
19
|
+
header: ProposedBlockHeader;
|
|
20
|
+
body: Body;
|
|
21
|
+
l1: L1PublishedData;
|
|
22
|
+
chainId: Fr;
|
|
23
|
+
version: Fr;
|
|
24
|
+
signatures: Signature[];
|
|
25
|
+
};
|
|
26
|
+
export declare function retrievedBlockToPublishedL2Block(retrievedBlock: RetrievedL2Block): PublishedL2Block;
|
|
12
27
|
/**
|
|
13
28
|
* Fetches new L2 blocks.
|
|
14
29
|
* @param publicClient - The viem public client to use for transaction retrieval.
|
|
@@ -18,16 +33,10 @@ import type { PublishedL2Block } from './structs/published.js';
|
|
|
18
33
|
* @param expectedNextL2BlockNum - The next L2 block number that we expect to find.
|
|
19
34
|
* @returns An array of block; as well as the next eth block to search from.
|
|
20
35
|
*/
|
|
21
|
-
export declare function retrieveBlocksFromRollup(rollup: GetContractReturnType<typeof RollupAbi, ViemPublicClient>, publicClient: ViemPublicClient, blobSinkClient: BlobSinkClientInterface, searchStartBlock: bigint, searchEndBlock: bigint, logger?: Logger): Promise<
|
|
22
|
-
/**
|
|
23
|
-
* Processes newly received L2BlockProposed logs.
|
|
24
|
-
* @param rollup - The rollup contract
|
|
25
|
-
* @param publicClient - The viem public client to use for transaction retrieval.
|
|
26
|
-
* @param logs - L2BlockProposed logs.
|
|
27
|
-
* @returns - An array blocks.
|
|
28
|
-
*/
|
|
29
|
-
export declare function processL2BlockProposedLogs(rollup: GetContractReturnType<typeof RollupAbi, ViemPublicClient>, publicClient: ViemPublicClient, blobSinkClient: BlobSinkClientInterface, logs: GetContractEventsReturnType<typeof RollupAbi, 'L2BlockProposed'>, logger: Logger): Promise<PublishedL2Block[]>;
|
|
36
|
+
export declare function retrieveBlocksFromRollup(rollup: GetContractReturnType<typeof RollupAbi, ViemPublicClient>, publicClient: ViemPublicClient, blobSinkClient: BlobSinkClientInterface, searchStartBlock: bigint, searchEndBlock: bigint, logger?: Logger): Promise<RetrievedL2Block[]>;
|
|
30
37
|
export declare function getL1BlockTime(publicClient: ViemPublicClient, blockNumber: bigint): Promise<bigint>;
|
|
38
|
+
/** Given an L1 to L2 message, retrieves its corresponding event from the Inbox. */
|
|
39
|
+
export declare function retrieveL1ToL2Message(inbox: GetContractReturnType<typeof InboxAbi, ViemClient>, leaf: Fr, fromBlock: bigint): Promise<InboxMessage | undefined>;
|
|
31
40
|
/**
|
|
32
41
|
* Fetch L1 to L2 messages.
|
|
33
42
|
* @param publicClient - The viem public client to use for transaction retrieval.
|
|
@@ -37,7 +46,7 @@ export declare function getL1BlockTime(publicClient: ViemPublicClient, blockNumb
|
|
|
37
46
|
* @param searchEndBlock - The highest block number that we should search up to.
|
|
38
47
|
* @returns An array of InboxLeaf and next eth block to search from.
|
|
39
48
|
*/
|
|
40
|
-
export declare function retrieveL1ToL2Messages(inbox: GetContractReturnType<typeof InboxAbi,
|
|
49
|
+
export declare function retrieveL1ToL2Messages(inbox: GetContractReturnType<typeof InboxAbi, ViemClient>, searchStartBlock: bigint, searchEndBlock: bigint): Promise<InboxMessage[]>;
|
|
41
50
|
/** Retrieves L2ProofVerified events from the rollup contract. */
|
|
42
51
|
export declare function retrieveL2ProofVerifiedEvents(publicClient: ViemPublicClient, rollupAddress: EthAddress, searchStartBlock: bigint, searchEndBlock?: bigint): Promise<{
|
|
43
52
|
l1BlockNumber: bigint;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"data_retrieval.d.ts","sourceRoot":"","sources":["../../src/archiver/data_retrieval.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,yBAAyB,CAAC;AACvE,OAAO,KAAK,EAA6B,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"data_retrieval.d.ts","sourceRoot":"","sources":["../../src/archiver/data_retrieval.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,yBAAyB,CAAC;AACvE,OAAO,KAAK,EAA6B,UAAU,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAG/F,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAChE,OAAO,EAAE,SAAS,EAAsB,MAAM,iCAAiC,CAAC;AAChF,OAAO,EAAE,EAAE,EAAE,MAAM,0BAA0B,CAAC;AAC9C,OAAO,EAAE,KAAK,MAAM,EAAgB,MAAM,uBAAuB,CAAC;AAClE,OAAO,EAAgB,KAAK,QAAQ,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAC7E,OAAO,EAAE,IAAI,EAAW,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,KAAK,EAAE,MAAM,sBAAsB,CAAC;AAE7C,OAAO,EAAgC,mBAAmB,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAErG,OAAO,EAEL,KAAK,qBAAqB,EAC1B,KAAK,GAAG,EAIT,MAAM,MAAM,CAAC;AAGd,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AACjE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAC/D,OAAO,KAAK,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAEhF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,EAAE,CAAC;IAChB,cAAc,EAAE,cAAc,CAAC;IAC/B,MAAM,EAAE,mBAAmB,CAAC;IAC5B,IAAI,EAAE,IAAI,CAAC;IACX,EAAE,EAAE,eAAe,CAAC;IACpB,OAAO,EAAE,EAAE,CAAC;IACZ,OAAO,EAAE,EAAE,CAAC;IACZ,UAAU,EAAE,SAAS,EAAE,CAAC;CACzB,CAAC;AAEF,wBAAgB,gCAAgC,CAAC,cAAc,EAAE,gBAAgB,GAAG,gBAAgB,CA6CnG;AAED;;;;;;;;GAQG;AACH,wBAAsB,wBAAwB,CAC5C,MAAM,EAAE,qBAAqB,CAAC,OAAO,SAAS,EAAE,gBAAgB,CAAC,EACjE,YAAY,EAAE,gBAAgB,EAC9B,cAAc,EAAE,uBAAuB,EACvC,gBAAgB,EAAE,MAAM,EACxB,cAAc,EAAE,MAAM,EACtB,MAAM,GAAE,MAAiC,GACxC,OAAO,CAAC,gBAAgB,EAAE,CAAC,CA+C7B;AA4DD,wBAAsB,cAAc,CAAC,YAAY,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAGzG;AAqID,mFAAmF;AACnF,wBAAsB,qBAAqB,CACzC,KAAK,EAAE,qBAAqB,CAAC,OAAO,QAAQ,EAAE,UAAU,CAAC,EACzD,IAAI,EAAE,EAAE,EACR,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,YAAY,GAAG,SAAS,CAAC,CAGnC;AAED;;;;;;;;GAQG;AACH,wBAAsB,sBAAsB,CAC1C,KAAK,EAAE,qBAAqB,CAAC,OAAO,QAAQ,EAAE,UAAU,CAAC,EACzD,gBAAgB,EAAE,MAAM,EACxB,cAAc,EAAE,MAAM,GACrB,OAAO,CAAC,YAAY,EAAE,CAAC,CAgBzB;AAgBD,iEAAiE;AACjE,wBAAsB,6BAA6B,CACjD,YAAY,EAAE,gBAAgB,EAC9B,aAAa,EAAE,UAAU,EACzB,gBAAgB,EAAE,MAAM,EACxB,cAAc,CAAC,EAAE,MAAM,GACtB,OAAO,CAAC;IAAE,aAAa,EAAE,MAAM,CAAC;IAAC,aAAa,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,EAAE,CAAC;IAAC,MAAM,EAAE,GAAG,CAAA;CAAE,EAAE,CAAC,CAexF;AAED,yDAAyD;AACzD,wBAAsB,0BAA0B,CAC9C,YAAY,EAAE,gBAAgB,EAC9B,aAAa,EAAE,UAAU,EACzB,gBAAgB,EAAE,MAAM,EACxB,cAAc,CAAC,EAAE,MAAM,GACtB,OAAO,CAAC,aAAa,CAAC;IAAE,KAAK,EAAE,KAAK,CAAC;IAAC,QAAQ,EAAE,EAAE,CAAC;IAAC,aAAa,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,KAAK,MAAM,EAAE,CAAA;CAAE,CAAC,CAAC,CAatG;AAED,MAAM,MAAM,gBAAgB,GAAG;IAC7B,WAAW,EAAE,EAAE,CAAC;IAChB,QAAQ,EAAE,EAAE,CAAC;IACb,KAAK,EAAE,KAAK,CAAC;CACd,CAAC;AAEF;;;;;;;;GAQG;AACH,wBAAsB,yBAAyB,CAC7C,YAAY,EAAE,gBAAgB,EAC9B,MAAM,EAAE,KAAK,MAAM,EAAE,EACrB,gBAAgB,EAAE,EAAE,GACnB,OAAO,CAAC,gBAAgB,CAAC,CAmC3B"}
|