@aztec/archiver 4.0.0-nightly.20260116 → 4.0.0-nightly.20260117
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/README.md +10 -2
- package/dest/archiver.d.ts +3 -2
- package/dest/archiver.d.ts.map +1 -1
- package/dest/archiver.js +7 -6
- package/dest/modules/data_source_base.d.ts +2 -1
- package/dest/modules/data_source_base.d.ts.map +1 -1
- package/dest/modules/data_source_base.js +3 -0
- package/dest/modules/data_store_updater.d.ts +29 -6
- package/dest/modules/data_store_updater.d.ts.map +1 -1
- package/dest/modules/data_store_updater.js +117 -29
- package/dest/modules/l1_synchronizer.d.ts +5 -3
- package/dest/modules/l1_synchronizer.d.ts.map +1 -1
- package/dest/modules/l1_synchronizer.js +98 -52
- package/dest/store/block_store.d.ts +16 -2
- package/dest/store/block_store.d.ts.map +1 -1
- package/dest/store/block_store.js +62 -8
- package/dest/store/kv_archiver_store.d.ts +14 -2
- package/dest/store/kv_archiver_store.d.ts.map +1 -1
- package/dest/store/kv_archiver_store.js +14 -0
- package/dest/store/log_store.d.ts +1 -1
- package/dest/store/log_store.d.ts.map +1 -1
- package/dest/store/log_store.js +69 -48
- package/dest/test/fake_l1_state.d.ts +18 -1
- package/dest/test/fake_l1_state.d.ts.map +1 -1
- package/dest/test/fake_l1_state.js +36 -17
- package/dest/test/mock_l2_block_source.d.ts +2 -1
- package/dest/test/mock_l2_block_source.d.ts.map +1 -1
- package/dest/test/mock_l2_block_source.js +4 -0
- package/package.json +13 -13
- package/src/archiver.ts +8 -6
- package/src/modules/data_source_base.ts +4 -0
- package/src/modules/data_store_updater.ts +143 -42
- package/src/modules/l1_synchronizer.ts +113 -61
- package/src/store/block_store.ts +79 -10
- package/src/store/kv_archiver_store.ts +19 -1
- package/src/store/log_store.ts +112 -76
- package/src/test/fake_l1_state.ts +62 -24
- package/src/test/mock_l2_block_source.ts +5 -0
package/src/store/block_store.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { INITIAL_CHECKPOINT_NUMBER, INITIAL_L2_BLOCK_NUM } from '@aztec/constants';
|
|
2
|
-
import { BlockNumber, CheckpointNumber } from '@aztec/foundation/branded-types';
|
|
2
|
+
import { BlockNumber, CheckpointNumber, SlotNumber } from '@aztec/foundation/branded-types';
|
|
3
3
|
import { Fr } from '@aztec/foundation/curves/bn254';
|
|
4
4
|
import { toArray } from '@aztec/foundation/iterable';
|
|
5
5
|
import { createLogger } from '@aztec/foundation/log';
|
|
@@ -350,6 +350,23 @@ export class BlockStore {
|
|
|
350
350
|
await this.#blockArchiveIndex.set(block.archive.root.toString(), block.number);
|
|
351
351
|
}
|
|
352
352
|
|
|
353
|
+
/** Deletes a block and all associated data (tx effects, indices). */
|
|
354
|
+
private async deleteBlock(block: L2BlockNew): Promise<void> {
|
|
355
|
+
// Delete the block from the main blocks map
|
|
356
|
+
await this.#blocks.delete(block.number);
|
|
357
|
+
|
|
358
|
+
// Delete all tx effects for this block
|
|
359
|
+
await Promise.all(block.body.txEffects.map(tx => this.#txEffects.delete(tx.txHash.toString())));
|
|
360
|
+
|
|
361
|
+
// Delete block txs mapping
|
|
362
|
+
const blockHash = (await block.hash()).toString();
|
|
363
|
+
await this.#blockTxs.delete(blockHash);
|
|
364
|
+
|
|
365
|
+
// Clean up indices
|
|
366
|
+
await this.#blockHashIndex.delete(blockHash);
|
|
367
|
+
await this.#blockArchiveIndex.delete(block.archive.root.toString());
|
|
368
|
+
}
|
|
369
|
+
|
|
353
370
|
/**
|
|
354
371
|
* Unwinds checkpoints from the database
|
|
355
372
|
* @param from - The tip of the chain, passed for verification purposes,
|
|
@@ -387,16 +404,11 @@ export class BlockStore {
|
|
|
387
404
|
this.#log.warn(`Cannot remove block ${blockNumber} from the store since we don't have it`);
|
|
388
405
|
continue;
|
|
389
406
|
}
|
|
390
|
-
await this.#blocks.delete(block.number);
|
|
391
|
-
await Promise.all(block.body.txEffects.map(tx => this.#txEffects.delete(tx.txHash.toString())));
|
|
392
|
-
const blockHash = (await block.hash()).toString();
|
|
393
|
-
await this.#blockTxs.delete(blockHash);
|
|
394
|
-
|
|
395
|
-
// Clean up indices
|
|
396
|
-
await this.#blockHashIndex.delete(blockHash);
|
|
397
|
-
await this.#blockArchiveIndex.delete(block.archive.root.toString());
|
|
398
407
|
|
|
399
|
-
this
|
|
408
|
+
await this.deleteBlock(block);
|
|
409
|
+
this.#log.debug(
|
|
410
|
+
`Unwound block ${blockNumber} ${(await block.hash()).toString()} for checkpoint ${checkpointNumber}`,
|
|
411
|
+
);
|
|
400
412
|
}
|
|
401
413
|
}
|
|
402
414
|
|
|
@@ -454,6 +466,61 @@ export class BlockStore {
|
|
|
454
466
|
return converted.filter(isDefined);
|
|
455
467
|
}
|
|
456
468
|
|
|
469
|
+
/**
|
|
470
|
+
* Gets all blocks that have the given slot number.
|
|
471
|
+
* Iterates backwards through blocks for efficiency since we usually query for the last slot.
|
|
472
|
+
* @param slotNumber - The slot number to search for.
|
|
473
|
+
* @returns All blocks with the given slot number, in ascending block number order.
|
|
474
|
+
*/
|
|
475
|
+
async getBlocksForSlot(slotNumber: SlotNumber): Promise<L2BlockNew[]> {
|
|
476
|
+
const blocks: L2BlockNew[] = [];
|
|
477
|
+
|
|
478
|
+
// Iterate backwards through all blocks and filter by slot number
|
|
479
|
+
// This is more efficient since we usually query for the most recent slot
|
|
480
|
+
for await (const [blockNumber, blockStorage] of this.#blocks.entriesAsync({ reverse: true })) {
|
|
481
|
+
const block = await this.getBlockFromBlockStorage(blockNumber, blockStorage);
|
|
482
|
+
const blockSlot = block?.header.globalVariables.slotNumber;
|
|
483
|
+
if (block && blockSlot === slotNumber) {
|
|
484
|
+
blocks.push(block);
|
|
485
|
+
} else if (blockSlot && blockSlot < slotNumber) {
|
|
486
|
+
break; // Blocks are stored in slot ascending order, so we can stop searching
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
// Reverse to return blocks in ascending order (block number order)
|
|
491
|
+
return blocks.reverse();
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
/**
|
|
495
|
+
* Removes all blocks with block number > blockNumber.
|
|
496
|
+
* @param blockNumber - The block number to remove after.
|
|
497
|
+
* @returns The removed blocks (for event emission).
|
|
498
|
+
*/
|
|
499
|
+
async unwindBlocksAfter(blockNumber: BlockNumber): Promise<L2BlockNew[]> {
|
|
500
|
+
return await this.db.transactionAsync(async () => {
|
|
501
|
+
const removedBlocks: L2BlockNew[] = [];
|
|
502
|
+
|
|
503
|
+
// Get the latest block number to determine the range
|
|
504
|
+
const latestBlockNumber = await this.getLatestBlockNumber();
|
|
505
|
+
|
|
506
|
+
// Iterate from blockNumber + 1 to latestBlockNumber
|
|
507
|
+
for (let bn = blockNumber + 1; bn <= latestBlockNumber; bn++) {
|
|
508
|
+
const block = await this.getBlock(BlockNumber(bn));
|
|
509
|
+
|
|
510
|
+
if (block === undefined) {
|
|
511
|
+
this.#log.warn(`Cannot remove block ${bn} from the store since we don't have it`);
|
|
512
|
+
continue;
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
removedBlocks.push(block);
|
|
516
|
+
await this.deleteBlock(block);
|
|
517
|
+
this.#log.debug(`Removed block ${bn} ${(await block.hash()).toString()}`);
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
return removedBlocks;
|
|
521
|
+
});
|
|
522
|
+
}
|
|
523
|
+
|
|
457
524
|
async getProvenBlockNumber(): Promise<BlockNumber> {
|
|
458
525
|
const provenCheckpointNumber = await this.getProvenCheckpointNumber();
|
|
459
526
|
if (provenCheckpointNumber === INITIAL_CHECKPOINT_NUMBER - 1) {
|
|
@@ -538,6 +605,7 @@ export class BlockStore {
|
|
|
538
605
|
}
|
|
539
606
|
return this.getCheckpointedBlock(BlockNumber(blockNumber));
|
|
540
607
|
}
|
|
608
|
+
|
|
541
609
|
async getCheckpointedBlockByArchive(archive: Fr): Promise<CheckpointedL2Block | undefined> {
|
|
542
610
|
const blockNumber = await this.#blockArchiveIndex.getAsync(archive.toString());
|
|
543
611
|
if (blockNumber === undefined) {
|
|
@@ -672,6 +740,7 @@ export class BlockStore {
|
|
|
672
740
|
const header = BlockHeader.fromBuffer(blockStorage.header);
|
|
673
741
|
const archive = AppendOnlyTreeSnapshot.fromBuffer(blockStorage.archive);
|
|
674
742
|
const blockHash = blockStorage.blockHash;
|
|
743
|
+
header.setHash(Fr.fromBuffer(blockHash));
|
|
675
744
|
const blockHashString = bufferToHex(blockHash);
|
|
676
745
|
const blockTxsBuffer = await this.#blockTxs.getAsync(blockHashString);
|
|
677
746
|
if (blockTxsBuffer === undefined) {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { L1BlockId } from '@aztec/ethereum/l1-types';
|
|
2
|
-
import type { BlockNumber, CheckpointNumber } from '@aztec/foundation/branded-types';
|
|
2
|
+
import type { BlockNumber, CheckpointNumber, SlotNumber } from '@aztec/foundation/branded-types';
|
|
3
3
|
import type { Fr } from '@aztec/foundation/curves/bn254';
|
|
4
4
|
import { toArray } from '@aztec/foundation/iterable';
|
|
5
5
|
import { createLogger } from '@aztec/foundation/log';
|
|
@@ -601,4 +601,22 @@ export class KVArchiverDataStore implements ContractDataSource {
|
|
|
601
601
|
getCheckpointData(checkpointNumber: CheckpointNumber): Promise<CheckpointData | undefined> {
|
|
602
602
|
return this.#blockStore.getCheckpointData(checkpointNumber);
|
|
603
603
|
}
|
|
604
|
+
|
|
605
|
+
/**
|
|
606
|
+
* Gets all blocks that have the given slot number.
|
|
607
|
+
* @param slotNumber - The slot number to search for.
|
|
608
|
+
* @returns All blocks with the given slot number.
|
|
609
|
+
*/
|
|
610
|
+
getBlocksForSlot(slotNumber: SlotNumber): Promise<L2BlockNew[]> {
|
|
611
|
+
return this.#blockStore.getBlocksForSlot(slotNumber);
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
/**
|
|
615
|
+
* Removes all blocks with block number > blockNumber.
|
|
616
|
+
* @param blockNumber - The block number to remove after.
|
|
617
|
+
* @returns The removed blocks (for event emission).
|
|
618
|
+
*/
|
|
619
|
+
removeBlocksAfter(blockNumber: BlockNumber): Promise<L2BlockNew[]> {
|
|
620
|
+
return this.#blockStore.unwindBlocksAfter(blockNumber);
|
|
621
|
+
}
|
|
604
622
|
}
|
package/src/store/log_store.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { INITIAL_L2_BLOCK_NUM } from '@aztec/constants';
|
|
2
2
|
import { BlockNumber } from '@aztec/foundation/branded-types';
|
|
3
|
+
import { filterAsync } from '@aztec/foundation/collection';
|
|
3
4
|
import { Fr } from '@aztec/foundation/curves/bn254';
|
|
4
5
|
import { createLogger } from '@aztec/foundation/log';
|
|
5
6
|
import { BufferReader, numToUInt32BE } from '@aztec/foundation/serialize';
|
|
@@ -144,92 +145,127 @@ export class LogStore {
|
|
|
144
145
|
return { privateTaggedLogs, publicTaggedLogs };
|
|
145
146
|
}
|
|
146
147
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
addLogs(blocks: L2BlockNew[]): Promise<boolean> {
|
|
153
|
-
const { privateTaggedLogs, publicTaggedLogs } = this.#extractTaggedLogs(blocks);
|
|
148
|
+
async #addPrivateLogs(blocks: L2BlockNew[]): Promise<void> {
|
|
149
|
+
const newBlocks = await filterAsync(
|
|
150
|
+
blocks,
|
|
151
|
+
async block => !(await this.#privateLogKeysByBlock.hasAsync(block.number)),
|
|
152
|
+
);
|
|
154
153
|
|
|
154
|
+
const { privateTaggedLogs } = this.#extractTaggedLogs(newBlocks);
|
|
155
155
|
const keysOfPrivateLogsToUpdate = Array.from(privateTaggedLogs.keys());
|
|
156
|
-
const keysOfPublicLogsToUpdate = Array.from(publicTaggedLogs.keys());
|
|
157
156
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
);
|
|
165
|
-
currentPrivateTaggedLogs.forEach(taggedLogBuffer => {
|
|
166
|
-
if (taggedLogBuffer.logBuffers && taggedLogBuffer.logBuffers.length > 0) {
|
|
167
|
-
privateTaggedLogs.set(
|
|
168
|
-
taggedLogBuffer.tag,
|
|
169
|
-
taggedLogBuffer.logBuffers!.concat(privateTaggedLogs.get(taggedLogBuffer.tag)!),
|
|
170
|
-
);
|
|
171
|
-
}
|
|
172
|
-
});
|
|
157
|
+
const currentPrivateTaggedLogs = await Promise.all(
|
|
158
|
+
keysOfPrivateLogsToUpdate.map(async key => ({
|
|
159
|
+
tag: key,
|
|
160
|
+
logBuffers: await this.#privateLogsByTag.getAsync(key),
|
|
161
|
+
})),
|
|
162
|
+
);
|
|
173
163
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
164
|
+
for (const taggedLogBuffer of currentPrivateTaggedLogs) {
|
|
165
|
+
if (taggedLogBuffer.logBuffers && taggedLogBuffer.logBuffers.length > 0) {
|
|
166
|
+
privateTaggedLogs.set(
|
|
167
|
+
taggedLogBuffer.tag,
|
|
168
|
+
taggedLogBuffer.logBuffers!.concat(privateTaggedLogs.get(taggedLogBuffer.tag)!),
|
|
169
|
+
);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
for (const block of newBlocks) {
|
|
174
|
+
const privateTagsInBlock: string[] = [];
|
|
175
|
+
for (const [tag, logs] of privateTaggedLogs.entries()) {
|
|
176
|
+
await this.#privateLogsByTag.set(tag, logs);
|
|
177
|
+
privateTagsInBlock.push(tag);
|
|
178
|
+
}
|
|
179
|
+
await this.#privateLogKeysByBlock.set(block.number, privateTagsInBlock);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
188
182
|
|
|
189
|
-
|
|
190
|
-
|
|
183
|
+
async #addPublicLogs(blocks: L2BlockNew[]): Promise<void> {
|
|
184
|
+
const newBlocks = await filterAsync(
|
|
185
|
+
blocks,
|
|
186
|
+
async block => !(await this.#publicLogKeysByBlock.hasAsync(block.number)),
|
|
187
|
+
);
|
|
191
188
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
await this.#privateLogsByTag.set(tag, logs);
|
|
195
|
-
privateTagsInBlock.push(tag);
|
|
196
|
-
}
|
|
197
|
-
await this.#privateLogKeysByBlock.set(block.number, privateTagsInBlock);
|
|
189
|
+
const { publicTaggedLogs } = this.#extractTaggedLogs(newBlocks);
|
|
190
|
+
const keysOfPublicLogsToUpdate = Array.from(publicTaggedLogs.keys());
|
|
198
191
|
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
txEffect.publicLogs.map(log => log.toBuffer()),
|
|
212
|
-
].flat(),
|
|
213
|
-
)
|
|
214
|
-
.flat();
|
|
215
|
-
|
|
216
|
-
const contractClassLogsInBlock = block.body.txEffects
|
|
217
|
-
.map((txEffect, txIndex) =>
|
|
218
|
-
[
|
|
219
|
-
numToUInt32BE(txIndex),
|
|
220
|
-
numToUInt32BE(txEffect.contractClassLogs.length),
|
|
221
|
-
txEffect.contractClassLogs.map(log => log.toBuffer()),
|
|
222
|
-
].flat(),
|
|
223
|
-
)
|
|
224
|
-
.flat();
|
|
225
|
-
|
|
226
|
-
await this.#publicLogsByBlock.set(block.number, this.#packWithBlockHash(blockHash, publicLogsInBlock));
|
|
227
|
-
await this.#contractClassLogsByBlock.set(
|
|
228
|
-
block.number,
|
|
229
|
-
this.#packWithBlockHash(blockHash, contractClassLogsInBlock),
|
|
192
|
+
const currentPublicTaggedLogs = await Promise.all(
|
|
193
|
+
keysOfPublicLogsToUpdate.map(async key => ({
|
|
194
|
+
tag: key,
|
|
195
|
+
logBuffers: await this.#publicLogsByContractAndTag.getAsync(key),
|
|
196
|
+
})),
|
|
197
|
+
);
|
|
198
|
+
|
|
199
|
+
for (const taggedLogBuffer of currentPublicTaggedLogs) {
|
|
200
|
+
if (taggedLogBuffer.logBuffers && taggedLogBuffer.logBuffers.length > 0) {
|
|
201
|
+
publicTaggedLogs.set(
|
|
202
|
+
taggedLogBuffer.tag,
|
|
203
|
+
taggedLogBuffer.logBuffers!.concat(publicTaggedLogs.get(taggedLogBuffer.tag)!),
|
|
230
204
|
);
|
|
231
205
|
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
for (const block of newBlocks) {
|
|
209
|
+
const blockHash = await block.hash();
|
|
210
|
+
const publicTagsInBlock: string[] = [];
|
|
211
|
+
for (const [tag, logs] of publicTaggedLogs.entries()) {
|
|
212
|
+
await this.#publicLogsByContractAndTag.set(tag, logs);
|
|
213
|
+
publicTagsInBlock.push(tag);
|
|
214
|
+
}
|
|
215
|
+
await this.#publicLogKeysByBlock.set(block.number, publicTagsInBlock);
|
|
216
|
+
|
|
217
|
+
const publicLogsInBlock = block.body.txEffects
|
|
218
|
+
.map((txEffect, txIndex) =>
|
|
219
|
+
[
|
|
220
|
+
numToUInt32BE(txIndex),
|
|
221
|
+
numToUInt32BE(txEffect.publicLogs.length),
|
|
222
|
+
txEffect.publicLogs.map(log => log.toBuffer()),
|
|
223
|
+
].flat(),
|
|
224
|
+
)
|
|
225
|
+
.flat();
|
|
226
|
+
|
|
227
|
+
await this.#publicLogsByBlock.set(block.number, this.#packWithBlockHash(blockHash, publicLogsInBlock));
|
|
228
|
+
}
|
|
229
|
+
}
|
|
232
230
|
|
|
231
|
+
async #addContractClassLogs(blocks: L2BlockNew[]): Promise<void> {
|
|
232
|
+
const newBlocks = await filterAsync(
|
|
233
|
+
blocks,
|
|
234
|
+
async block => !(await this.#contractClassLogsByBlock.hasAsync(block.number)),
|
|
235
|
+
);
|
|
236
|
+
|
|
237
|
+
for (const block of newBlocks) {
|
|
238
|
+
const blockHash = await block.hash();
|
|
239
|
+
|
|
240
|
+
const contractClassLogsInBlock = block.body.txEffects
|
|
241
|
+
.map((txEffect, txIndex) =>
|
|
242
|
+
[
|
|
243
|
+
numToUInt32BE(txIndex),
|
|
244
|
+
numToUInt32BE(txEffect.contractClassLogs.length),
|
|
245
|
+
txEffect.contractClassLogs.map(log => log.toBuffer()),
|
|
246
|
+
].flat(),
|
|
247
|
+
)
|
|
248
|
+
.flat();
|
|
249
|
+
|
|
250
|
+
await this.#contractClassLogsByBlock.set(
|
|
251
|
+
block.number,
|
|
252
|
+
this.#packWithBlockHash(blockHash, contractClassLogsInBlock),
|
|
253
|
+
);
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
/**
|
|
258
|
+
* Append new logs to the store's list.
|
|
259
|
+
* @param blocks - The blocks for which to add the logs.
|
|
260
|
+
* @returns True if the operation is successful.
|
|
261
|
+
*/
|
|
262
|
+
addLogs(blocks: L2BlockNew[]): Promise<boolean> {
|
|
263
|
+
return this.db.transactionAsync(async () => {
|
|
264
|
+
await Promise.all([
|
|
265
|
+
this.#addPrivateLogs(blocks),
|
|
266
|
+
this.#addPublicLogs(blocks),
|
|
267
|
+
this.#addContractClassLogs(blocks),
|
|
268
|
+
]);
|
|
233
269
|
return true;
|
|
234
270
|
});
|
|
235
271
|
}
|
|
@@ -10,8 +10,9 @@ import { Fr } from '@aztec/foundation/curves/bn254';
|
|
|
10
10
|
import { EthAddress } from '@aztec/foundation/eth-address';
|
|
11
11
|
import { createLogger } from '@aztec/foundation/log';
|
|
12
12
|
import { RollupAbi } from '@aztec/l1-artifacts';
|
|
13
|
-
import { CommitteeAttestation, CommitteeAttestationsAndSigners } from '@aztec/stdlib/block';
|
|
13
|
+
import { CommitteeAttestation, CommitteeAttestationsAndSigners, L2BlockNew } from '@aztec/stdlib/block';
|
|
14
14
|
import { Checkpoint } from '@aztec/stdlib/checkpoint';
|
|
15
|
+
import { getSlotAtTimestamp } from '@aztec/stdlib/epoch-helpers';
|
|
15
16
|
import { InboxLeaf } from '@aztec/stdlib/messaging';
|
|
16
17
|
import {
|
|
17
18
|
makeAndSignCommitteeAttestationsAndSigners,
|
|
@@ -39,6 +40,8 @@ export type FakeL1StateConfig = {
|
|
|
39
40
|
rollupAddress: EthAddress;
|
|
40
41
|
/** Inbox address for mock contracts. */
|
|
41
42
|
inboxAddress: EthAddress;
|
|
43
|
+
/** Aztec slot duration in seconds */
|
|
44
|
+
slotDuration: number;
|
|
42
45
|
};
|
|
43
46
|
|
|
44
47
|
/** Options for adding a checkpoint. */
|
|
@@ -47,6 +50,8 @@ type AddCheckpointOptions = {
|
|
|
47
50
|
l1BlockNumber: bigint;
|
|
48
51
|
/** Number of L2 blocks in the checkpoint. Default: 1 */
|
|
49
52
|
numBlocks?: number;
|
|
53
|
+
/** Or the actual blocks for the checkpoint */
|
|
54
|
+
blocks?: L2BlockNew[];
|
|
50
55
|
/** Number of transactions per block. Default: 4 */
|
|
51
56
|
txsPerBlock?: number;
|
|
52
57
|
/** Max number of effects per tx (for generating large blobs). Default: undefined */
|
|
@@ -157,38 +162,32 @@ export class FakeL1State {
|
|
|
157
162
|
});
|
|
158
163
|
}
|
|
159
164
|
|
|
165
|
+
/**
|
|
166
|
+
* Creates blocks for a checkpoint without adding them to L1 state.
|
|
167
|
+
* Useful for creating blocks to pass to addBlock() for testing provisional block handling.
|
|
168
|
+
* Returns the blocks directly.
|
|
169
|
+
*/
|
|
170
|
+
public async makeBlocks(checkpointNumber: CheckpointNumber, options: Partial<AddCheckpointOptions>) {
|
|
171
|
+
return (await this.makeCheckpointAndMessages(checkpointNumber, options)).checkpoint.blocks;
|
|
172
|
+
}
|
|
173
|
+
|
|
160
174
|
/**
|
|
161
175
|
* Creates and adds a checkpoint with its L1-to-L2 messages.
|
|
162
176
|
* Returns both the checkpoint and the message leaves.
|
|
163
177
|
* Auto-chains from lastArchive, auto-updates pending status if L1 block >= checkpoint's L1 block.
|
|
164
178
|
*/
|
|
165
|
-
async addCheckpoint(
|
|
179
|
+
public async addCheckpoint(
|
|
180
|
+
checkpointNumber: CheckpointNumber,
|
|
181
|
+
options: AddCheckpointOptions,
|
|
182
|
+
): Promise<AddCheckpointResult> {
|
|
166
183
|
this.log.warn(`Adding checkpoint ${checkpointNumber}`);
|
|
167
184
|
|
|
168
|
-
const {
|
|
169
|
-
l1BlockNumber,
|
|
170
|
-
numBlocks = 1,
|
|
171
|
-
txsPerBlock = 4,
|
|
172
|
-
maxEffects,
|
|
173
|
-
signers = [],
|
|
174
|
-
slotNumber,
|
|
175
|
-
previousArchive = this.lastArchive,
|
|
176
|
-
timestamp,
|
|
177
|
-
numL1ToL2Messages = 3,
|
|
178
|
-
messagesL1BlockNumber = l1BlockNumber - 3n,
|
|
179
|
-
} = options;
|
|
185
|
+
const { l1BlockNumber, signers = [], messagesL1BlockNumber = l1BlockNumber - 3n } = options;
|
|
180
186
|
|
|
181
187
|
// Create the checkpoint using the stdlib helper
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
numBlocks,
|
|
186
|
-
numTxsPerBlock: txsPerBlock,
|
|
187
|
-
numL1ToL2Messages,
|
|
188
|
-
previousArchive,
|
|
189
|
-
...(slotNumber !== undefined ? { slotNumber } : {}),
|
|
190
|
-
...(timestamp !== undefined ? { timestamp } : {}),
|
|
191
|
-
...(maxEffects !== undefined ? { maxEffects } : {}),
|
|
188
|
+
const { checkpoint, messages, lastArchive } = await this.makeCheckpointAndMessages(checkpointNumber, {
|
|
189
|
+
...options,
|
|
190
|
+
numL1ToL2Messages: options.numL1ToL2Messages ?? 3,
|
|
192
191
|
});
|
|
193
192
|
|
|
194
193
|
// Store the messages internally so they match the checkpoint's inHash
|
|
@@ -219,6 +218,45 @@ export class FakeL1State {
|
|
|
219
218
|
return { checkpoint, messages };
|
|
220
219
|
}
|
|
221
220
|
|
|
221
|
+
/** Creates a checkpoint and messages without adding them to L1 state. */
|
|
222
|
+
private makeCheckpointAndMessages(checkpointNumber: CheckpointNumber, options: Partial<AddCheckpointOptions>) {
|
|
223
|
+
const {
|
|
224
|
+
numBlocks = 1,
|
|
225
|
+
txsPerBlock = 4,
|
|
226
|
+
maxEffects,
|
|
227
|
+
slotNumber,
|
|
228
|
+
previousArchive = this.lastArchive,
|
|
229
|
+
timestamp,
|
|
230
|
+
l1BlockNumber,
|
|
231
|
+
numL1ToL2Messages = 0,
|
|
232
|
+
blocks,
|
|
233
|
+
} = options;
|
|
234
|
+
|
|
235
|
+
return mockCheckpointAndMessages(checkpointNumber, {
|
|
236
|
+
startBlockNumber: this.getNextBlockNumber(checkpointNumber),
|
|
237
|
+
numBlocks,
|
|
238
|
+
blocks,
|
|
239
|
+
numTxsPerBlock: txsPerBlock,
|
|
240
|
+
numL1ToL2Messages,
|
|
241
|
+
previousArchive,
|
|
242
|
+
slotNumber: slotNumber ?? (l1BlockNumber !== undefined ? this.getL2SlotAtL1Block(l1BlockNumber) : undefined),
|
|
243
|
+
timestamp: timestamp ?? (l1BlockNumber !== undefined ? this.getTimestampAtL1Block(l1BlockNumber) : undefined),
|
|
244
|
+
...(maxEffects !== undefined ? { maxEffects } : {}),
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/** Returns the L2 slot at the given L1 block (assuming all L1 blocks are mined) */
|
|
249
|
+
public getL2SlotAtL1Block(l1BlockNumber: bigint): SlotNumber {
|
|
250
|
+
const timestamp = this.getTimestampAtL1Block(l1BlockNumber);
|
|
251
|
+
return getSlotAtTimestamp(timestamp, this.config);
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
/** Returns the timestamp at the given L1 block (assuming all L1 blocks are mined) */
|
|
255
|
+
public getTimestampAtL1Block(l1BlockNumber: bigint): bigint {
|
|
256
|
+
const { l1GenesisTime, l1StartBlock, ethereumSlotDuration } = this.config;
|
|
257
|
+
return l1GenesisTime + (l1BlockNumber - l1StartBlock) * BigInt(ethereumSlotDuration);
|
|
258
|
+
}
|
|
259
|
+
|
|
222
260
|
/**
|
|
223
261
|
* Sets the current L1 block number.
|
|
224
262
|
* Auto-updates pending checkpoint number based on visible checkpoints.
|
|
@@ -255,6 +255,11 @@ export class MockL2BlockSource implements L2BlockSource, ContractDataSource {
|
|
|
255
255
|
return Promise.resolve(blocks);
|
|
256
256
|
}
|
|
257
257
|
|
|
258
|
+
getBlocksForSlot(slotNumber: SlotNumber): Promise<L2BlockNew[]> {
|
|
259
|
+
const blocks = this.l2Blocks.filter(b => b.header.globalVariables.slotNumber === slotNumber);
|
|
260
|
+
return Promise.resolve(blocks.map(b => b.toL2Block()));
|
|
261
|
+
}
|
|
262
|
+
|
|
258
263
|
async getBlockHeadersForEpoch(epochNumber: EpochNumber): Promise<BlockHeader[]> {
|
|
259
264
|
const blocks = await this.getBlocksForEpoch(epochNumber);
|
|
260
265
|
return blocks.map(b => b.getBlockHeader());
|