@aztec/archiver 0.0.1-commit.d431d1c → 0.0.1-commit.d939eb5aa

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 (116) hide show
  1. package/README.md +21 -6
  2. package/dest/archiver.d.ts +17 -12
  3. package/dest/archiver.d.ts.map +1 -1
  4. package/dest/archiver.js +108 -127
  5. package/dest/config.d.ts +3 -3
  6. package/dest/config.d.ts.map +1 -1
  7. package/dest/config.js +3 -2
  8. package/dest/errors.d.ts +39 -10
  9. package/dest/errors.d.ts.map +1 -1
  10. package/dest/errors.js +52 -15
  11. package/dest/factory.d.ts +4 -2
  12. package/dest/factory.d.ts.map +1 -1
  13. package/dest/factory.js +29 -23
  14. package/dest/index.d.ts +2 -1
  15. package/dest/index.d.ts.map +1 -1
  16. package/dest/index.js +1 -0
  17. package/dest/l1/bin/retrieve-calldata.js +35 -32
  18. package/dest/l1/calldata_retriever.d.ts +73 -50
  19. package/dest/l1/calldata_retriever.d.ts.map +1 -1
  20. package/dest/l1/calldata_retriever.js +191 -259
  21. package/dest/l1/data_retrieval.d.ts +11 -11
  22. package/dest/l1/data_retrieval.d.ts.map +1 -1
  23. package/dest/l1/data_retrieval.js +38 -37
  24. package/dest/l1/spire_proposer.d.ts +5 -5
  25. package/dest/l1/spire_proposer.d.ts.map +1 -1
  26. package/dest/l1/spire_proposer.js +9 -17
  27. package/dest/l1/validate_trace.d.ts +6 -3
  28. package/dest/l1/validate_trace.d.ts.map +1 -1
  29. package/dest/l1/validate_trace.js +13 -9
  30. package/dest/modules/data_source_base.d.ts +29 -23
  31. package/dest/modules/data_source_base.d.ts.map +1 -1
  32. package/dest/modules/data_source_base.js +55 -124
  33. package/dest/modules/data_store_updater.d.ts +43 -26
  34. package/dest/modules/data_store_updater.d.ts.map +1 -1
  35. package/dest/modules/data_store_updater.js +158 -129
  36. package/dest/modules/instrumentation.d.ts +19 -4
  37. package/dest/modules/instrumentation.d.ts.map +1 -1
  38. package/dest/modules/instrumentation.js +53 -18
  39. package/dest/modules/l1_synchronizer.d.ts +7 -9
  40. package/dest/modules/l1_synchronizer.d.ts.map +1 -1
  41. package/dest/modules/l1_synchronizer.js +186 -145
  42. package/dest/modules/validation.d.ts +1 -1
  43. package/dest/modules/validation.d.ts.map +1 -1
  44. package/dest/modules/validation.js +2 -2
  45. package/dest/store/block_store.d.ts +86 -34
  46. package/dest/store/block_store.d.ts.map +1 -1
  47. package/dest/store/block_store.js +414 -152
  48. package/dest/store/contract_class_store.d.ts +2 -3
  49. package/dest/store/contract_class_store.d.ts.map +1 -1
  50. package/dest/store/contract_class_store.js +16 -72
  51. package/dest/store/contract_instance_store.d.ts +1 -1
  52. package/dest/store/contract_instance_store.d.ts.map +1 -1
  53. package/dest/store/contract_instance_store.js +6 -2
  54. package/dest/store/kv_archiver_store.d.ts +80 -39
  55. package/dest/store/kv_archiver_store.d.ts.map +1 -1
  56. package/dest/store/kv_archiver_store.js +86 -35
  57. package/dest/store/l2_tips_cache.d.ts +20 -0
  58. package/dest/store/l2_tips_cache.d.ts.map +1 -0
  59. package/dest/store/l2_tips_cache.js +109 -0
  60. package/dest/store/log_store.d.ts +9 -6
  61. package/dest/store/log_store.d.ts.map +1 -1
  62. package/dest/store/log_store.js +151 -56
  63. package/dest/store/message_store.d.ts +5 -1
  64. package/dest/store/message_store.d.ts.map +1 -1
  65. package/dest/store/message_store.js +21 -9
  66. package/dest/test/fake_l1_state.d.ts +24 -4
  67. package/dest/test/fake_l1_state.d.ts.map +1 -1
  68. package/dest/test/fake_l1_state.js +133 -26
  69. package/dest/test/index.js +3 -1
  70. package/dest/test/mock_archiver.d.ts +1 -1
  71. package/dest/test/mock_archiver.d.ts.map +1 -1
  72. package/dest/test/mock_archiver.js +3 -2
  73. package/dest/test/mock_l1_to_l2_message_source.d.ts +1 -1
  74. package/dest/test/mock_l1_to_l2_message_source.d.ts.map +1 -1
  75. package/dest/test/mock_l1_to_l2_message_source.js +2 -1
  76. package/dest/test/mock_l2_block_source.d.ts +44 -23
  77. package/dest/test/mock_l2_block_source.d.ts.map +1 -1
  78. package/dest/test/mock_l2_block_source.js +185 -115
  79. package/dest/test/mock_structs.d.ts +6 -2
  80. package/dest/test/mock_structs.d.ts.map +1 -1
  81. package/dest/test/mock_structs.js +24 -10
  82. package/dest/test/noop_l1_archiver.d.ts +26 -0
  83. package/dest/test/noop_l1_archiver.d.ts.map +1 -0
  84. package/dest/test/noop_l1_archiver.js +71 -0
  85. package/package.json +14 -13
  86. package/src/archiver.ts +144 -159
  87. package/src/config.ts +9 -2
  88. package/src/errors.ts +82 -26
  89. package/src/factory.ts +46 -22
  90. package/src/index.ts +1 -0
  91. package/src/l1/README.md +25 -68
  92. package/src/l1/bin/retrieve-calldata.ts +45 -33
  93. package/src/l1/calldata_retriever.ts +250 -379
  94. package/src/l1/data_retrieval.ts +35 -41
  95. package/src/l1/spire_proposer.ts +7 -15
  96. package/src/l1/validate_trace.ts +24 -6
  97. package/src/modules/data_source_base.ts +98 -169
  98. package/src/modules/data_store_updater.ts +178 -160
  99. package/src/modules/instrumentation.ts +64 -20
  100. package/src/modules/l1_synchronizer.ts +212 -182
  101. package/src/modules/validation.ts +2 -2
  102. package/src/store/block_store.ts +533 -207
  103. package/src/store/contract_class_store.ts +16 -110
  104. package/src/store/contract_instance_store.ts +8 -5
  105. package/src/store/kv_archiver_store.ts +141 -59
  106. package/src/store/l2_tips_cache.ts +134 -0
  107. package/src/store/log_store.ts +232 -74
  108. package/src/store/message_store.ts +27 -10
  109. package/src/structs/inbox_message.ts +1 -1
  110. package/src/test/fake_l1_state.ts +180 -32
  111. package/src/test/index.ts +3 -0
  112. package/src/test/mock_archiver.ts +3 -2
  113. package/src/test/mock_l1_to_l2_message_source.ts +1 -0
  114. package/src/test/mock_l2_block_source.ts +247 -130
  115. package/src/test/mock_structs.ts +45 -15
  116. package/src/test/noop_l1_archiver.ts +114 -0
@@ -8,48 +8,97 @@ import { createLogger } from '@aztec/foundation/log';
8
8
  import type { FunctionSelector } from '@aztec/stdlib/abi';
9
9
  import type { AztecAddress } from '@aztec/stdlib/aztec-address';
10
10
  import {
11
+ type BlockData,
12
+ BlockHash,
11
13
  CheckpointedL2Block,
12
- L2BlockHash,
13
- L2BlockNew,
14
+ L2Block,
14
15
  type L2BlockSource,
15
16
  type L2Tips,
16
17
  type ValidateCheckpointResult,
17
18
  } from '@aztec/stdlib/block';
18
- import { Checkpoint, L1PublishedData, PublishedCheckpoint } from '@aztec/stdlib/checkpoint';
19
+ import {
20
+ Checkpoint,
21
+ type CheckpointData,
22
+ L1PublishedData,
23
+ type ProposedCheckpointData,
24
+ PublishedCheckpoint,
25
+ } from '@aztec/stdlib/checkpoint';
19
26
  import type { ContractClassPublic, ContractDataSource, ContractInstanceWithAddress } from '@aztec/stdlib/contract';
20
- import { EmptyL1RollupConstants, type L1RollupConstants, getSlotRangeForEpoch } from '@aztec/stdlib/epoch-helpers';
21
- import { type BlockHeader, TxHash, TxReceipt, TxStatus } from '@aztec/stdlib/tx';
27
+ import {
28
+ EmptyL1RollupConstants,
29
+ type L1RollupConstants,
30
+ getEpochAtSlot,
31
+ getSlotRangeForEpoch,
32
+ } from '@aztec/stdlib/epoch-helpers';
33
+ import { computeCheckpointOutHash } from '@aztec/stdlib/messaging';
34
+ import { CheckpointHeader } from '@aztec/stdlib/rollup';
35
+ import { type BlockHeader, TxExecutionResult, TxHash, TxReceipt, TxStatus } from '@aztec/stdlib/tx';
22
36
  import type { UInt64 } from '@aztec/stdlib/types';
23
37
 
24
38
  /**
25
39
  * A mocked implementation of L2BlockSource to be used in tests.
26
40
  */
27
41
  export class MockL2BlockSource implements L2BlockSource, ContractDataSource {
28
- protected l2Blocks: L2BlockNew[] = [];
42
+ protected l2Blocks: L2Block[] = [];
43
+ protected checkpointList: Checkpoint[] = [];
29
44
 
30
45
  private provenBlockNumber: number = 0;
31
46
  private finalizedBlockNumber: number = 0;
32
47
  private checkpointedBlockNumber: number = 0;
48
+ private proposedCheckpointBlockNumber: number = 0;
33
49
 
34
50
  private log = createLogger('archiver:mock_l2_block_source');
35
51
 
52
+ /** Creates blocks grouped into single-block checkpoints. */
36
53
  public async createBlocks(numBlocks: number) {
37
- for (let i = 0; i < numBlocks; i++) {
38
- const blockNum = this.l2Blocks.length + 1;
39
- const block = await L2BlockNew.random(BlockNumber(blockNum), { slotNumber: SlotNumber(blockNum) });
40
- this.l2Blocks.push(block);
54
+ await this.createCheckpoints(numBlocks, 1);
55
+ }
56
+
57
+ public getCheckpointNumber(): Promise<CheckpointNumber> {
58
+ return Promise.resolve(
59
+ this.checkpointList.length === 0 ? CheckpointNumber.ZERO : CheckpointNumber(this.checkpointList.length),
60
+ );
61
+ }
62
+
63
+ /** Creates checkpoints, each containing `blocksPerCheckpoint` blocks. */
64
+ public async createCheckpoints(numCheckpoints: number, blocksPerCheckpoint: number = 1) {
65
+ for (let c = 0; c < numCheckpoints; c++) {
66
+ const checkpointNum = CheckpointNumber(this.checkpointList.length + 1);
67
+ const startBlockNum = this.l2Blocks.length + 1;
68
+ const slotNumber = SlotNumber(Number(checkpointNum));
69
+ const checkpoint = await Checkpoint.random(checkpointNum, {
70
+ numBlocks: blocksPerCheckpoint,
71
+ startBlockNumber: startBlockNum,
72
+ slotNumber,
73
+ checkpointNumber: checkpointNum,
74
+ });
75
+ this.checkpointList.push(checkpoint);
76
+ this.l2Blocks.push(...checkpoint.blocks);
41
77
  }
42
78
 
43
- this.log.verbose(`Created ${numBlocks} blocks in the mock L2 block source`);
79
+ this.log.verbose(
80
+ `Created ${numCheckpoints} checkpoints with ${blocksPerCheckpoint} blocks each in the mock L2 block source`,
81
+ );
44
82
  }
45
83
 
46
- public addBlocks(blocks: L2BlockNew[]) {
84
+ public addProposedBlocks(blocks: L2Block[]) {
47
85
  this.l2Blocks.push(...blocks);
48
- this.log.verbose(`Added ${blocks.length} blocks to the mock L2 block source`);
86
+ this.log.verbose(`Added ${blocks.length} proposed blocks to the mock L2 block source`);
49
87
  }
50
88
 
51
89
  public removeBlocks(numBlocks: number) {
52
90
  this.l2Blocks = this.l2Blocks.slice(0, -numBlocks);
91
+ const maxBlockNum = this.l2Blocks.length;
92
+ // Remove any checkpoint whose last block is beyond the remaining blocks.
93
+ this.checkpointList = this.checkpointList.filter(c => {
94
+ const lastBlockNum = c.blocks[0].number + c.blocks.length - 1;
95
+ return lastBlockNum <= maxBlockNum;
96
+ });
97
+ // Keep tip numbers consistent with remaining blocks.
98
+ this.checkpointedBlockNumber = Math.min(this.checkpointedBlockNumber, maxBlockNum);
99
+ this.proposedCheckpointBlockNumber = Math.min(this.proposedCheckpointBlockNumber, maxBlockNum);
100
+ this.provenBlockNumber = Math.min(this.provenBlockNumber, maxBlockNum);
101
+ this.finalizedBlockNumber = Math.min(this.finalizedBlockNumber, maxBlockNum);
53
102
  this.log.verbose(`Removed ${numBlocks} blocks from the mock L2 block source`);
54
103
  }
55
104
 
@@ -64,8 +113,42 @@ export class MockL2BlockSource implements L2BlockSource, ContractDataSource {
64
113
  this.finalizedBlockNumber = finalizedBlockNumber;
65
114
  }
66
115
 
116
+ public setProposedCheckpointBlockNumber(blockNumber: number) {
117
+ this.proposedCheckpointBlockNumber = blockNumber;
118
+ }
119
+
67
120
  public setCheckpointedBlockNumber(checkpointedBlockNumber: number) {
121
+ const prevCheckpointed = this.checkpointedBlockNumber;
68
122
  this.checkpointedBlockNumber = checkpointedBlockNumber;
123
+ // Proposed checkpoint is always at least as advanced as checkpointed
124
+ if (this.proposedCheckpointBlockNumber < checkpointedBlockNumber) {
125
+ this.proposedCheckpointBlockNumber = checkpointedBlockNumber;
126
+ }
127
+ // Auto-create single-block checkpoints for newly checkpointed blocks that don't have one yet.
128
+ // This handles blocks added via addProposedBlocks that are now being marked as checkpointed.
129
+ const newCheckpoints: Checkpoint[] = [];
130
+ for (let blockNum = prevCheckpointed + 1; blockNum <= checkpointedBlockNumber; blockNum++) {
131
+ const block = this.l2Blocks[blockNum - 1];
132
+ if (!block) {
133
+ continue;
134
+ }
135
+ if (this.checkpointList.some(c => c.blocks.some(b => b.number === block.number))) {
136
+ continue;
137
+ }
138
+ const checkpointNum = CheckpointNumber(this.checkpointList.length + newCheckpoints.length + 1);
139
+ const checkpoint = new Checkpoint(
140
+ block.archive,
141
+ CheckpointHeader.random({ slotNumber: block.header.globalVariables.slotNumber }),
142
+ [block],
143
+ checkpointNum,
144
+ );
145
+ newCheckpoints.push(checkpoint);
146
+ }
147
+ // Insert new checkpoints in order by number.
148
+ if (newCheckpoints.length > 0) {
149
+ this.checkpointList.push(...newCheckpoints);
150
+ this.checkpointList.sort((a, b) => a.number - b.number);
151
+ }
69
152
  }
70
153
 
71
154
  /**
@@ -96,6 +179,18 @@ export class MockL2BlockSource implements L2BlockSource, ContractDataSource {
96
179
  return Promise.resolve(BlockNumber(this.provenBlockNumber));
97
180
  }
98
181
 
182
+ public getCheckpointedL2BlockNumber() {
183
+ return Promise.resolve(BlockNumber(this.checkpointedBlockNumber));
184
+ }
185
+
186
+ public getFinalizedL2BlockNumber() {
187
+ return Promise.resolve(BlockNumber(this.finalizedBlockNumber));
188
+ }
189
+
190
+ public getProposedCheckpointL2BlockNumber() {
191
+ return Promise.resolve(BlockNumber(this.proposedCheckpointBlockNumber));
192
+ }
193
+
99
194
  public getCheckpointedBlock(number: BlockNumber): Promise<CheckpointedL2Block | undefined> {
100
195
  if (number > this.checkpointedBlockNumber) {
101
196
  return Promise.resolve(undefined);
@@ -104,20 +199,10 @@ export class MockL2BlockSource implements L2BlockSource, ContractDataSource {
104
199
  if (!block) {
105
200
  return Promise.resolve(undefined);
106
201
  }
107
- const checkpointedBlock = new CheckpointedL2Block(
108
- CheckpointNumber(number),
109
- block,
110
- new L1PublishedData(BigInt(number), BigInt(number), `0x${number.toString(16).padStart(64, '0')}`),
111
- [],
112
- );
113
- return Promise.resolve(checkpointedBlock);
202
+ return Promise.resolve(this.toCheckpointedBlock(block));
114
203
  }
115
204
 
116
- public async getCheckpointedBlocks(
117
- from: BlockNumber,
118
- limit: number,
119
- _proven?: boolean,
120
- ): Promise<CheckpointedL2Block[]> {
205
+ public async getCheckpointedBlocks(from: BlockNumber, limit: number): Promise<CheckpointedL2Block[]> {
121
206
  const result: CheckpointedL2Block[] = [];
122
207
  for (let i = 0; i < limit; i++) {
123
208
  const blockNum = from + i;
@@ -137,7 +222,7 @@ export class MockL2BlockSource implements L2BlockSource, ContractDataSource {
137
222
  * @param number - The block number to return (inclusive).
138
223
  * @returns The requested L2 block.
139
224
  */
140
- public getBlock(number: number): Promise<L2BlockNew | undefined> {
225
+ public getBlock(number: number): Promise<L2Block | undefined> {
141
226
  const block = this.l2Blocks[number - 1];
142
227
  return Promise.resolve(block);
143
228
  }
@@ -147,7 +232,7 @@ export class MockL2BlockSource implements L2BlockSource, ContractDataSource {
147
232
  * @param number - The block number to return.
148
233
  * @returns The requested L2 block.
149
234
  */
150
- public getL2BlockNew(number: BlockNumber): Promise<L2BlockNew | undefined> {
235
+ public getL2Block(number: BlockNumber): Promise<L2Block | undefined> {
151
236
  const block = this.l2Blocks[number - 1];
152
237
  return Promise.resolve(block);
153
238
  }
@@ -158,95 +243,41 @@ export class MockL2BlockSource implements L2BlockSource, ContractDataSource {
158
243
  * @param limit - The maximum number of blocks to return.
159
244
  * @returns The requested mocked L2 blocks.
160
245
  */
161
- public getBlocks(from: number, limit: number, proven?: boolean): Promise<L2BlockNew[]> {
162
- return Promise.resolve(
163
- this.l2Blocks
164
- .slice(from - 1, from - 1 + limit)
165
- .filter(b => !proven || this.provenBlockNumber === undefined || b.number <= this.provenBlockNumber),
166
- );
167
- }
168
-
169
- public getPublishedCheckpoints(from: CheckpointNumber, limit: number) {
170
- // TODO(mbps): Implement this properly. This only works when we have one block per checkpoint.
171
- const blocks = this.l2Blocks.slice(from - 1, from - 1 + limit);
172
- return Promise.all(
173
- blocks.map(async block => {
174
- // Create a checkpoint from the block - manually construct since L2BlockNew doesn't have toCheckpoint()
175
- const checkpoint = await Checkpoint.random(block.checkpointNumber, { numBlocks: 1 });
176
- checkpoint.blocks = [block];
177
- return new PublishedCheckpoint(
178
- checkpoint,
179
- new L1PublishedData(BigInt(block.number), BigInt(block.number), Buffer32.random().toString()),
180
- [],
181
- );
182
- }),
183
- );
184
- }
185
-
186
- public async getCheckpointByArchive(archive: Fr): Promise<Checkpoint | undefined> {
187
- // TODO(mbps): Implement this properly. This only works when we have one block per checkpoint.
188
- const block = this.l2Blocks.find(b => b.archive.root.equals(archive));
189
- if (!block) {
190
- return undefined;
191
- }
192
- // Create a checkpoint from the block - manually construct since L2BlockNew doesn't have toCheckpoint()
193
- const checkpoint = await Checkpoint.random(block.checkpointNumber, { numBlocks: 1 });
194
- checkpoint.blocks = [block];
195
- return checkpoint;
246
+ public getBlocks(from: number, limit: number): Promise<L2Block[]> {
247
+ return Promise.resolve(this.l2Blocks.slice(from - 1, from - 1 + limit));
196
248
  }
197
249
 
198
- public getPublishedBlocks(from: number, limit: number, proven?: boolean): Promise<CheckpointedL2Block[]> {
199
- const blocks = this.l2Blocks
200
- .slice(from - 1, from - 1 + limit)
201
- .filter(b => !proven || this.provenBlockNumber === undefined || b.number <= this.provenBlockNumber);
250
+ public getCheckpoints(from: CheckpointNumber, limit: number) {
251
+ const checkpoints = this.checkpointList.slice(from - 1, from - 1 + limit);
202
252
  return Promise.resolve(
203
- blocks.map(block =>
204
- CheckpointedL2Block.fromFields({
205
- checkpointNumber: CheckpointNumber(block.number),
206
- block,
207
- l1: new L1PublishedData(BigInt(block.number), BigInt(block.number), Buffer32.random().toString()),
208
- attestations: [],
209
- }),
210
- ),
253
+ checkpoints.map(checkpoint => new PublishedCheckpoint(checkpoint, this.mockL1DataForCheckpoint(checkpoint), [])),
211
254
  );
212
255
  }
213
256
 
214
- getL2BlocksNew(from: BlockNumber, limit: number, proven?: boolean): Promise<L2BlockNew[]> {
215
- // getBlocks already returns L2BlockNew[], so just return directly
216
- return this.getBlocks(from, limit, proven);
257
+ public getCheckpointByArchive(archive: Fr): Promise<Checkpoint | undefined> {
258
+ const checkpoint = this.checkpointList.find(c => c.archive.root.equals(archive));
259
+ return Promise.resolve(checkpoint);
217
260
  }
218
261
 
219
- public async getPublishedBlockByHash(blockHash: Fr): Promise<CheckpointedL2Block | undefined> {
262
+ public async getCheckpointedBlockByHash(blockHash: BlockHash): Promise<CheckpointedL2Block | undefined> {
220
263
  for (const block of this.l2Blocks) {
221
264
  const hash = await block.hash();
222
265
  if (hash.equals(blockHash)) {
223
- return CheckpointedL2Block.fromFields({
224
- checkpointNumber: CheckpointNumber(block.number),
225
- block,
226
- l1: new L1PublishedData(BigInt(block.number), BigInt(block.number), Buffer32.random().toString()),
227
- attestations: [],
228
- });
266
+ return this.toCheckpointedBlock(block);
229
267
  }
230
268
  }
231
269
  return undefined;
232
270
  }
233
271
 
234
- public getPublishedBlockByArchive(archive: Fr): Promise<CheckpointedL2Block | undefined> {
272
+ public getCheckpointedBlockByArchive(archive: Fr): Promise<CheckpointedL2Block | undefined> {
235
273
  const block = this.l2Blocks.find(b => b.archive.root.equals(archive));
236
274
  if (!block) {
237
275
  return Promise.resolve(undefined);
238
276
  }
239
- return Promise.resolve(
240
- CheckpointedL2Block.fromFields({
241
- checkpointNumber: CheckpointNumber(block.number),
242
- block,
243
- l1: new L1PublishedData(BigInt(block.number), BigInt(block.number), Buffer32.random().toString()),
244
- attestations: [],
245
- }),
246
- );
277
+ return Promise.resolve(this.toCheckpointedBlock(block));
247
278
  }
248
279
 
249
- public async getL2BlockNewByHash(blockHash: Fr): Promise<L2BlockNew | undefined> {
280
+ public async getL2BlockByHash(blockHash: BlockHash): Promise<L2Block | undefined> {
250
281
  for (const block of this.l2Blocks) {
251
282
  const hash = await block.hash();
252
283
  if (hash.equals(blockHash)) {
@@ -256,12 +287,12 @@ export class MockL2BlockSource implements L2BlockSource, ContractDataSource {
256
287
  return undefined;
257
288
  }
258
289
 
259
- public getL2BlockNewByArchive(archive: Fr): Promise<L2BlockNew | undefined> {
290
+ public getL2BlockByArchive(archive: Fr): Promise<L2Block | undefined> {
260
291
  const block = this.l2Blocks.find(b => b.archive.root.equals(archive));
261
292
  return Promise.resolve(block);
262
293
  }
263
294
 
264
- public async getBlockHeaderByHash(blockHash: Fr): Promise<BlockHeader | undefined> {
295
+ public async getBlockHeaderByHash(blockHash: BlockHash): Promise<BlockHeader | undefined> {
265
296
  for (const block of this.l2Blocks) {
266
297
  const hash = await block.hash();
267
298
  if (hash.equals(blockHash)) {
@@ -276,46 +307,77 @@ export class MockL2BlockSource implements L2BlockSource, ContractDataSource {
276
307
  return Promise.resolve(block?.header);
277
308
  }
278
309
 
310
+ public async getBlockData(number: BlockNumber): Promise<BlockData | undefined> {
311
+ const block = this.l2Blocks[number - 1];
312
+ if (!block) {
313
+ return undefined;
314
+ }
315
+ return {
316
+ header: block.header,
317
+ archive: block.archive,
318
+ blockHash: await block.hash(),
319
+ checkpointNumber: block.checkpointNumber,
320
+ indexWithinCheckpoint: block.indexWithinCheckpoint,
321
+ };
322
+ }
323
+
324
+ public async getBlockDataByArchive(archive: Fr): Promise<BlockData | undefined> {
325
+ const block = this.l2Blocks.find(b => b.archive.root.equals(archive));
326
+ if (!block) {
327
+ return undefined;
328
+ }
329
+ return {
330
+ header: block.header,
331
+ archive: block.archive,
332
+ blockHash: await block.hash(),
333
+ checkpointNumber: block.checkpointNumber,
334
+ indexWithinCheckpoint: block.indexWithinCheckpoint,
335
+ };
336
+ }
337
+
279
338
  getBlockHeader(number: number | 'latest'): Promise<BlockHeader | undefined> {
280
339
  return Promise.resolve(this.l2Blocks.at(typeof number === 'number' ? number - 1 : -1)?.header);
281
340
  }
282
341
 
283
342
  getCheckpointsForEpoch(epochNumber: EpochNumber): Promise<Checkpoint[]> {
284
- // TODO(mbps): Implement this properly. This only works when we have one block per checkpoint.
285
- const epochDuration = DefaultL1ContractsConfig.aztecEpochDuration;
286
- const [start, end] = getSlotRangeForEpoch(epochNumber, { epochDuration });
287
- const blocks = this.l2Blocks.filter(b => {
288
- const slot = b.header.globalVariables.slotNumber;
289
- return slot >= start && slot <= end;
290
- });
291
- // Create checkpoints from blocks - manually construct since L2BlockNew doesn't have toCheckpoint()
292
- return Promise.all(
293
- blocks.map(async block => {
294
- const checkpoint = await Checkpoint.random(block.checkpointNumber, { numBlocks: 1 });
295
- checkpoint.blocks = [block];
296
- return checkpoint;
297
- }),
343
+ return Promise.resolve(this.getCheckpointsInEpoch(epochNumber));
344
+ }
345
+
346
+ getCheckpointsDataForEpoch(epochNumber: EpochNumber): Promise<CheckpointData[]> {
347
+ const checkpoints = this.getCheckpointsInEpoch(epochNumber);
348
+ return Promise.resolve(
349
+ checkpoints.map(
350
+ (checkpoint): CheckpointData => ({
351
+ checkpointNumber: checkpoint.number,
352
+ header: checkpoint.header,
353
+ archive: checkpoint.archive,
354
+ checkpointOutHash: computeCheckpointOutHash(
355
+ checkpoint.blocks.map(b => b.body.txEffects.map(tx => tx.l2ToL1Msgs)),
356
+ ),
357
+ startBlock: checkpoint.blocks[0].number,
358
+ blockCount: checkpoint.blocks.length,
359
+ attestations: [],
360
+ l1: this.mockL1DataForCheckpoint(checkpoint),
361
+ }),
362
+ ),
298
363
  );
299
364
  }
300
365
 
301
- getBlocksForEpoch(epochNumber: EpochNumber): Promise<L2BlockNew[]> {
302
- const epochDuration = DefaultL1ContractsConfig.aztecEpochDuration;
303
- const [start, end] = getSlotRangeForEpoch(epochNumber, { epochDuration });
304
- const blocks = this.l2Blocks.filter(b => {
305
- const slot = b.header.globalVariables.slotNumber;
306
- return slot >= start && slot <= end;
307
- });
308
- return Promise.resolve(blocks);
366
+ getCheckpointedBlocksForEpoch(epochNumber: EpochNumber): Promise<CheckpointedL2Block[]> {
367
+ const checkpoints = this.getCheckpointsInEpoch(epochNumber);
368
+ return Promise.resolve(
369
+ checkpoints.flatMap(checkpoint => checkpoint.blocks.map(block => this.toCheckpointedBlock(block))),
370
+ );
309
371
  }
310
372
 
311
- getBlocksForSlot(slotNumber: SlotNumber): Promise<L2BlockNew[]> {
373
+ getBlocksForSlot(slotNumber: SlotNumber): Promise<L2Block[]> {
312
374
  const blocks = this.l2Blocks.filter(b => b.header.globalVariables.slotNumber === slotNumber);
313
375
  return Promise.resolve(blocks);
314
376
  }
315
377
 
316
- async getBlockHeadersForEpoch(epochNumber: EpochNumber): Promise<BlockHeader[]> {
317
- const blocks = await this.getBlocksForEpoch(epochNumber);
318
- return blocks.map(b => b.header);
378
+ async getCheckpointedBlockHeadersForEpoch(epochNumber: EpochNumber): Promise<BlockHeader[]> {
379
+ const checkpointedBlocks = await this.getCheckpointedBlocksForEpoch(epochNumber);
380
+ return checkpointedBlocks.map(b => b.block.header);
319
381
  }
320
382
 
321
383
  /**
@@ -334,7 +396,7 @@ export class MockL2BlockSource implements L2BlockSource, ContractDataSource {
334
396
  return {
335
397
  data: txEffect,
336
398
  l2BlockNumber: block.number,
337
- l2BlockHash: L2BlockHash.fromField(await block.hash()),
399
+ l2BlockHash: await block.hash(),
338
400
  txIndexInBlock: block.body.txEffects.indexOf(txEffect),
339
401
  };
340
402
  }
@@ -348,13 +410,16 @@ export class MockL2BlockSource implements L2BlockSource, ContractDataSource {
348
410
  for (const block of this.l2Blocks) {
349
411
  for (const txEffect of block.body.txEffects) {
350
412
  if (txEffect.txHash.equals(txHash)) {
413
+ // In mock, assume all txs are checkpointed with successful execution
351
414
  return new TxReceipt(
352
415
  txHash,
353
- TxStatus.SUCCESS,
354
- '',
416
+ TxStatus.CHECKPOINTED,
417
+ TxExecutionResult.SUCCESS,
418
+ undefined,
355
419
  txEffect.transactionFee.toBigInt(),
356
- L2BlockHash.fromField(await block.hash()),
420
+ await block.hash(),
357
421
  block.number,
422
+ getEpochAtSlot(block.slot, EmptyL1RollupConstants),
358
423
  );
359
424
  }
360
425
  }
@@ -363,17 +428,19 @@ export class MockL2BlockSource implements L2BlockSource, ContractDataSource {
363
428
  }
364
429
 
365
430
  async getL2Tips(): Promise<L2Tips> {
366
- const [latest, proven, finalized, checkpointed] = [
431
+ const [latest, proven, finalized, checkpointed, proposedCheckpoint] = [
367
432
  await this.getBlockNumber(),
368
433
  await this.getProvenBlockNumber(),
369
434
  this.finalizedBlockNumber,
370
435
  this.checkpointedBlockNumber,
436
+ await this.getProposedCheckpointL2BlockNumber(),
371
437
  ] as const;
372
438
 
373
439
  const latestBlock = this.l2Blocks[latest - 1];
374
440
  const provenBlock = this.l2Blocks[proven - 1];
375
441
  const finalizedBlock = this.l2Blocks[finalized - 1];
376
442
  const checkpointedBlock = this.l2Blocks[checkpointed - 1];
443
+ const proposedCheckpointBlock = this.l2Blocks[proposedCheckpoint - 1];
377
444
 
378
445
  const latestBlockId = {
379
446
  number: BlockNumber(latest),
@@ -391,10 +458,17 @@ export class MockL2BlockSource implements L2BlockSource, ContractDataSource {
391
458
  number: BlockNumber(checkpointed),
392
459
  hash: (await checkpointedBlock?.hash())?.toString(),
393
460
  };
461
+ const proposedCheckpointBlockId = {
462
+ number: BlockNumber(proposedCheckpoint),
463
+ hash: (await proposedCheckpointBlock?.hash())?.toString(),
464
+ };
394
465
 
395
466
  const makeTipId = (blockId: typeof latestBlockId) => ({
396
467
  block: blockId,
397
- checkpoint: { number: CheckpointNumber(blockId.number), hash: blockId.hash },
468
+ checkpoint: {
469
+ number: this.findCheckpointNumberForBlock(blockId.number) ?? CheckpointNumber(0),
470
+ hash: blockId.hash,
471
+ },
398
472
  });
399
473
 
400
474
  return {
@@ -402,14 +476,15 @@ export class MockL2BlockSource implements L2BlockSource, ContractDataSource {
402
476
  checkpointed: makeTipId(checkpointedBlockId),
403
477
  proven: makeTipId(provenBlockId),
404
478
  finalized: makeTipId(finalizedBlockId),
479
+ proposedCheckpoint: makeTipId(proposedCheckpointBlockId),
405
480
  };
406
481
  }
407
482
 
408
- getL2EpochNumber(): Promise<EpochNumber> {
483
+ getSyncedL2EpochNumber(): Promise<EpochNumber> {
409
484
  throw new Error('Method not implemented.');
410
485
  }
411
486
 
412
- getL2SlotNumber(): Promise<SlotNumber> {
487
+ getSyncedL2SlotNumber(): Promise<SlotNumber> {
413
488
  throw new Error('Method not implemented.');
414
489
  }
415
490
 
@@ -482,4 +557,46 @@ export class MockL2BlockSource implements L2BlockSource, ContractDataSource {
482
557
  getPendingChainValidationStatus(): Promise<ValidateCheckpointResult> {
483
558
  return Promise.resolve({ valid: true });
484
559
  }
560
+
561
+ getProposedCheckpoint(): Promise<ProposedCheckpointData | undefined> {
562
+ return Promise.resolve(undefined);
563
+ }
564
+
565
+ getProposedCheckpointOnly(): Promise<ProposedCheckpointData | undefined> {
566
+ return Promise.resolve(undefined);
567
+ }
568
+
569
+ /** Returns checkpoints whose slot falls within the given epoch. */
570
+ private getCheckpointsInEpoch(epochNumber: EpochNumber): Checkpoint[] {
571
+ const epochDuration = DefaultL1ContractsConfig.aztecEpochDuration;
572
+ const [start, end] = getSlotRangeForEpoch(epochNumber, { epochDuration });
573
+ return this.checkpointList.filter(c => c.header.slotNumber >= start && c.header.slotNumber <= end);
574
+ }
575
+
576
+ /** Creates a mock L1PublishedData for a checkpoint. */
577
+ private mockL1DataForCheckpoint(checkpoint: Checkpoint): L1PublishedData {
578
+ return new L1PublishedData(BigInt(checkpoint.number), BigInt(checkpoint.number), Buffer32.random().toString());
579
+ }
580
+
581
+ /** Creates a CheckpointedL2Block from a block using stored checkpoint info. */
582
+ private toCheckpointedBlock(block: L2Block): CheckpointedL2Block {
583
+ const checkpoint = this.checkpointList.find(c => c.blocks.some(b => b.number === block.number));
584
+ const checkpointNumber = checkpoint?.number ?? block.checkpointNumber;
585
+ return new CheckpointedL2Block(
586
+ checkpointNumber,
587
+ block,
588
+ new L1PublishedData(
589
+ BigInt(block.number),
590
+ BigInt(block.number),
591
+ `0x${block.number.toString(16).padStart(64, '0')}`,
592
+ ),
593
+ [],
594
+ );
595
+ }
596
+
597
+ /** Finds the checkpoint number for a block, or undefined if the block is not in any checkpoint. */
598
+ private findCheckpointNumberForBlock(blockNumber: BlockNumber): CheckpointNumber | undefined {
599
+ const checkpoint = this.checkpointList.find(c => c.blocks.some(b => b.number === blockNumber));
600
+ return checkpoint?.number;
601
+ }
485
602
  }
@@ -12,7 +12,7 @@ import type { Secp256k1Signer } from '@aztec/foundation/crypto/secp256k1-signer'
12
12
  import { Fr } from '@aztec/foundation/curves/bn254';
13
13
  import { EthAddress } from '@aztec/foundation/eth-address';
14
14
  import { AztecAddress } from '@aztec/stdlib/aztec-address';
15
- import { CommitteeAttestation, L2BlockNew } from '@aztec/stdlib/block';
15
+ import { CommitteeAttestation, L2Block } from '@aztec/stdlib/block';
16
16
  import { Checkpoint, L1PublishedData, PublishedCheckpoint } from '@aztec/stdlib/checkpoint';
17
17
  import { PrivateLog, PublicLog, SiloedTag, Tag } from '@aztec/stdlib/logs';
18
18
  import { InboxLeaf } from '@aztec/stdlib/messaging';
@@ -46,24 +46,40 @@ export function makeInboxMessage(
46
46
  }
47
47
 
48
48
  export function makeInboxMessages(
49
- count: number,
49
+ totalCount: number,
50
50
  opts: {
51
51
  initialHash?: Buffer16;
52
52
  initialCheckpointNumber?: CheckpointNumber;
53
+ messagesPerCheckpoint?: number;
53
54
  overrideFn?: (msg: InboxMessage, index: number) => InboxMessage;
54
55
  } = {},
55
56
  ): InboxMessage[] {
56
- const { initialHash = Buffer16.ZERO, overrideFn = msg => msg, initialCheckpointNumber = 1 } = opts;
57
+ const {
58
+ initialHash = Buffer16.ZERO,
59
+ overrideFn = msg => msg,
60
+ initialCheckpointNumber = CheckpointNumber(1),
61
+ messagesPerCheckpoint = 1,
62
+ } = opts;
63
+
57
64
  const messages: InboxMessage[] = [];
58
65
  let rollingHash = initialHash;
59
- for (let i = 0; i < count; i++) {
66
+ for (let i = 0; i < totalCount; i++) {
67
+ const msgIndex = i % messagesPerCheckpoint;
68
+ const checkpointNumber = CheckpointNumber.fromBigInt(
69
+ BigInt(initialCheckpointNumber) + BigInt(i) / BigInt(messagesPerCheckpoint),
70
+ );
60
71
  const leaf = Fr.random();
61
- const checkpointNumber = CheckpointNumber(i + initialCheckpointNumber);
62
- const message = overrideFn(makeInboxMessage(rollingHash, { leaf, checkpointNumber }), i);
72
+ const message = overrideFn(
73
+ makeInboxMessage(rollingHash, {
74
+ leaf,
75
+ checkpointNumber,
76
+ index: InboxLeaf.smallestIndexForCheckpoint(checkpointNumber) + BigInt(msgIndex),
77
+ }),
78
+ i,
79
+ );
63
80
  rollingHash = message.rollingHash;
64
81
  messages.push(message);
65
82
  }
66
-
67
83
  return messages;
68
84
  }
69
85
 
@@ -111,6 +127,25 @@ export function makeL1PublishedData(l1BlockNumber: number): L1PublishedData {
111
127
  return new L1PublishedData(BigInt(l1BlockNumber), BigInt(l1BlockNumber * 1000), makeBlockHash(l1BlockNumber));
112
128
  }
113
129
 
130
+ /** Creates a Checkpoint from a list of blocks with a header that matches the blocks' structure. */
131
+ export function makeCheckpoint(blocks: L2Block[], checkpointNumber = CheckpointNumber(1)): Checkpoint {
132
+ const firstBlock = blocks[0];
133
+ const { slotNumber, timestamp, coinbase, feeRecipient, gasFees } = firstBlock.header.globalVariables;
134
+ return new Checkpoint(
135
+ blocks.at(-1)!.archive,
136
+ CheckpointHeader.random({
137
+ lastArchiveRoot: firstBlock.header.lastArchive.root,
138
+ slotNumber,
139
+ timestamp,
140
+ coinbase,
141
+ feeRecipient,
142
+ gasFees,
143
+ }),
144
+ blocks,
145
+ checkpointNumber,
146
+ );
147
+ }
148
+
114
149
  /** Wraps a Checkpoint with L1 published data and random attestations. */
115
150
  export function makePublishedCheckpoint(
116
151
  checkpoint: Checkpoint,
@@ -268,8 +303,8 @@ export async function makeCheckpointWithLogs(
268
303
  ): Promise<PublishedCheckpoint> {
269
304
  const { previousArchive, numTxsPerBlock = 4, privateLogs, publicLogs } = options;
270
305
 
271
- const block = await L2BlockNew.random(BlockNumber(blockNumber), {
272
- checkpointNumber: CheckpointNumber(blockNumber),
306
+ const block = await L2Block.random(BlockNumber(blockNumber), {
307
+ checkpointNumber: CheckpointNumber.fromBlockNumber(BlockNumber(blockNumber)),
273
308
  indexWithinCheckpoint: IndexWithinCheckpoint(0),
274
309
  state: makeStateForBlock(blockNumber, numTxsPerBlock),
275
310
  ...(previousArchive ? { lastArchive: previousArchive } : {}),
@@ -285,11 +320,6 @@ export async function makeCheckpointWithLogs(
285
320
  return txEffect;
286
321
  });
287
322
 
288
- const checkpoint = new Checkpoint(
289
- AppendOnlyTreeSnapshot.random(),
290
- CheckpointHeader.random(),
291
- [block],
292
- CheckpointNumber(blockNumber),
293
- );
323
+ const checkpoint = makeCheckpoint([block], CheckpointNumber.fromBlockNumber(BlockNumber(blockNumber)));
294
324
  return makePublishedCheckpoint(checkpoint, blockNumber);
295
325
  }