@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.
Files changed (57) hide show
  1. package/dest/archiver/archiver.d.ts +62 -5
  2. package/dest/archiver/archiver.d.ts.map +1 -1
  3. package/dest/archiver/archiver.js +362 -91
  4. package/dest/archiver/archiver_store.d.ts +33 -17
  5. package/dest/archiver/archiver_store.d.ts.map +1 -1
  6. package/dest/archiver/archiver_store_test_suite.d.ts.map +1 -1
  7. package/dest/archiver/archiver_store_test_suite.js +364 -62
  8. package/dest/archiver/data_retrieval.d.ts +23 -14
  9. package/dest/archiver/data_retrieval.d.ts.map +1 -1
  10. package/dest/archiver/data_retrieval.js +86 -38
  11. package/dest/archiver/errors.d.ts +8 -0
  12. package/dest/archiver/errors.d.ts.map +1 -1
  13. package/dest/archiver/errors.js +12 -0
  14. package/dest/archiver/instrumentation.d.ts.map +1 -1
  15. package/dest/archiver/kv_archiver_store/block_store.d.ts +4 -1
  16. package/dest/archiver/kv_archiver_store/block_store.d.ts.map +1 -1
  17. package/dest/archiver/kv_archiver_store/block_store.js +43 -6
  18. package/dest/archiver/kv_archiver_store/contract_instance_store.d.ts +3 -1
  19. package/dest/archiver/kv_archiver_store/contract_instance_store.d.ts.map +1 -1
  20. package/dest/archiver/kv_archiver_store/contract_instance_store.js +17 -3
  21. package/dest/archiver/kv_archiver_store/kv_archiver_store.d.ts +24 -14
  22. package/dest/archiver/kv_archiver_store/kv_archiver_store.d.ts.map +1 -1
  23. package/dest/archiver/kv_archiver_store/kv_archiver_store.js +37 -11
  24. package/dest/archiver/kv_archiver_store/log_store.d.ts.map +1 -1
  25. package/dest/archiver/kv_archiver_store/log_store.js +1 -1
  26. package/dest/archiver/kv_archiver_store/message_store.d.ts +21 -15
  27. package/dest/archiver/kv_archiver_store/message_store.d.ts.map +1 -1
  28. package/dest/archiver/kv_archiver_store/message_store.js +150 -48
  29. package/dest/archiver/structs/inbox_message.d.ts +14 -0
  30. package/dest/archiver/structs/inbox_message.d.ts.map +1 -0
  31. package/dest/archiver/structs/inbox_message.js +38 -0
  32. package/dest/rpc/index.d.ts +1 -1
  33. package/dest/test/mock_l2_block_source.d.ts +2 -0
  34. package/dest/test/mock_l2_block_source.d.ts.map +1 -1
  35. package/dest/test/mock_l2_block_source.js +8 -1
  36. package/dest/test/mock_structs.d.ts +9 -0
  37. package/dest/test/mock_structs.d.ts.map +1 -0
  38. package/dest/test/mock_structs.js +37 -0
  39. package/package.json +15 -15
  40. package/src/archiver/archiver.ts +431 -108
  41. package/src/archiver/archiver_store.ts +37 -18
  42. package/src/archiver/archiver_store_test_suite.ts +307 -52
  43. package/src/archiver/data_retrieval.ts +130 -53
  44. package/src/archiver/errors.ts +21 -0
  45. package/src/archiver/instrumentation.ts +4 -1
  46. package/src/archiver/kv_archiver_store/block_store.ts +46 -8
  47. package/src/archiver/kv_archiver_store/contract_instance_store.ts +20 -7
  48. package/src/archiver/kv_archiver_store/kv_archiver_store.ts +61 -17
  49. package/src/archiver/kv_archiver_store/log_store.ts +6 -2
  50. package/src/archiver/kv_archiver_store/message_store.ts +209 -53
  51. package/src/archiver/structs/inbox_message.ts +40 -0
  52. package/src/test/mock_l2_block_source.ts +9 -1
  53. package/src/test/mock_structs.ts +49 -0
  54. package/dest/archiver/memory_archiver_store/l1_to_l2_message_store.d.ts +0 -23
  55. package/dest/archiver/memory_archiver_store/l1_to_l2_message_store.d.ts.map +0 -1
  56. package/dest/archiver/memory_archiver_store/l1_to_l2_message_store.js +0 -49
  57. package/src/archiver/memory_archiver_store/l1_to_l2_message_store.ts +0 -61
@@ -1,8 +1,11 @@
1
- import { INITIAL_L2_BLOCK_NUM, L1_TO_L2_MSG_SUBTREE_HEIGHT, PRIVATE_LOG_SIZE_IN_FIELDS, PUBLIC_LOG_DATA_SIZE_IN_FIELDS } from '@aztec/constants';
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.getBlocks(blockNumber, 1), [
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.getBlocks(blockNumber, 1)).toEqual([]);
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.getBlocks(1, 10)).map((b)=>b.block.number)).toEqual([
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.getBlocks(start, limit), getExpectedBlocks());
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.getBlocks(12, 1)).resolves.toEqual([]);
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.getBlocks(1, 0)).rejects.toThrow('Invalid limit: 0');
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.getBlocks(INITIAL_L2_BLOCK_NUM - 100, 1)).rejects.toThrow('Invalid start: -99');
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
- await store.addL1ToL2Messages({
155
- lastProcessedL1BlockNumber: 1n,
156
- retrievedData: [
157
- new InboxLeaf(1n, Fr.ZERO)
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: 1n
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 l2BlockNumber = 13n;
286
- const l1ToL2MessageSubtreeSize = 2 ** L1_TO_L2_MSG_SUBTREE_HEIGHT;
287
- const generateBlockMessages = (blockNumber, numMessages)=>Array.from({
288
- length: numMessages
289
- }, (_, i)=>new InboxLeaf(InboxLeaf.smallestIndexFromL2Block(blockNumber) + BigInt(i), Fr.random()));
290
- it('returns messages in correct order', async ()=>{
291
- const msgs = generateBlockMessages(l2BlockNumber, l1ToL2MessageSubtreeSize);
292
- const shuffledMessages = msgs.slice().sort(()=>randomInt(1) - 0.5);
293
- await store.addL1ToL2Messages({
294
- lastProcessedL1BlockNumber: 100n,
295
- retrievedData: shuffledMessages
296
- });
297
- const retrievedMessages = await store.getL1ToL2Messages(l2BlockNumber);
298
- const expectedLeavesOrder = msgs.map((msg)=>msg.leaf);
299
- expect(expectedLeavesOrder).toEqual(retrievedMessages);
300
- });
301
- it('throws if it is impossible to sequence messages correctly', async ()=>{
302
- const msgs = generateBlockMessages(l2BlockNumber, l1ToL2MessageSubtreeSize - 1);
303
- // We replace a message with index 4 with a message with index at the end of the tree
304
- // --> with that there will be a gap and it will be impossible to sequence the
305
- // end of tree = start of next tree/block - 1
306
- msgs[4] = new InboxLeaf(InboxLeaf.smallestIndexFromL2Block(l2BlockNumber + 1n) - 1n, Fr.random());
307
- await store.addL1ToL2Messages({
308
- lastProcessedL1BlockNumber: 100n,
309
- retrievedData: msgs
310
- });
311
- await expect(async ()=>{
312
- await store.getL1ToL2Messages(l2BlockNumber);
313
- }).rejects.toThrow(`L1 to L2 message gap found in block ${l2BlockNumber}`);
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)=>new Fr((blockNumber * 100 + txIndex * 10 + logIndex) * (isPublic ? 123 : 1));
458
- const makePrivateLog = (tag)=>PrivateLog.fromFields([
459
- tag,
460
- ...times(PRIVATE_LOG_SIZE_IN_FIELDS - 1, (i)=>new Fr(tag.toNumber() + i))
461
- ]);
462
- const makePublicLog = (tag)=>PublicLog.fromFields([
463
- AztecAddress.fromNumber(1).toField(),
464
- tag,
465
- ...times(PUBLIC_LOG_DATA_SIZE_IN_FIELDS - 1, (i)=>new Fr(tag.toNumber() + i))
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(1, 1, 2),
506
- makeTag(0, 2, 0)
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: 1,
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: 0,
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(0, 0, 0) is shared with the first private log and the first public log.
829
+ // Tag(1, 0, 0) is shared with the first private log and the first public log.
528
830
  const tags = [
529
- makeTag(0, 0, 0)
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: 0,
837
+ blockNumber: 1,
536
838
  log: makePrivateLog(tags[0]),
537
839
  isFromPublic: false
538
840
  }),
539
841
  expect.objectContaining({
540
- blockNumber: 0,
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 { InboxLeaf } from '@aztec/stdlib/messaging';
8
+ import { Body } from '@aztec/stdlib/block';
8
9
  import { Proof } from '@aztec/stdlib/proofs';
9
- import { type GetContractEventsReturnType, type GetContractReturnType, type Hex } from 'viem';
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 { PublishedL2Block } from './structs/published.js';
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<PublishedL2Block[]>;
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, ViemPublicClient>, searchStartBlock: bigint, searchEndBlock: bigint): Promise<DataRetrieval<InboxLeaf>>;
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;AAEnF,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAEhE,OAAO,EAAE,EAAE,EAAE,MAAM,0BAA0B,CAAC;AAC9C,OAAO,EAAE,KAAK,MAAM,EAAgB,MAAM,uBAAuB,CAAC;AAElE,OAAO,EAAgB,KAAK,QAAQ,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAE7E,OAAO,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AACpD,OAAO,EAAE,KAAK,EAAE,MAAM,sBAAsB,CAAC;AAI7C,OAAO,EACL,KAAK,2BAA2B,EAChC,KAAK,qBAAqB,EAC1B,KAAK,GAAG,EAIT,MAAM,MAAM,CAAC;AAGd,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AACjE,OAAO,KAAK,EAAmB,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAEhF;;;;;;;;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,CAsC7B;AAED;;;;;;GAMG;AACH,wBAAsB,0BAA0B,CAC9C,MAAM,EAAE,qBAAqB,CAAC,OAAO,SAAS,EAAE,gBAAgB,CAAC,EACjE,YAAY,EAAE,gBAAgB,EAC9B,cAAc,EAAE,uBAAuB,EACvC,IAAI,EAAE,2BAA2B,CAAC,OAAO,SAAS,EAAE,iBAAiB,CAAC,EACtE,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,gBAAgB,EAAE,CAAC,CA0C7B;AAED,wBAAsB,cAAc,CAAC,YAAY,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAGzG;AAuID;;;;;;;;GAQG;AACH,wBAAsB,sBAAsB,CAC1C,KAAK,EAAE,qBAAqB,CAAC,OAAO,QAAQ,EAAE,gBAAgB,CAAC,EAC/D,gBAAgB,EAAE,MAAM,EACxB,cAAc,EAAE,MAAM,GACrB,OAAO,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC,CA8BnC;AAED,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"}
1
+ {"version":3,"file":"data_retrieval.d.ts","sourceRoot":"","sources":["../../src/archiver/data_retrieval.ts"],"names":[],"mappings":"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"}