@aztec/archiver 3.0.0-nightly.20251208 → 3.0.0-nightly.20251210
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dest/archiver/archiver.d.ts +8 -9
- package/dest/archiver/archiver.d.ts.map +1 -1
- package/dest/archiver/archiver.js +31 -18
- package/dest/archiver/archiver_store.d.ts +8 -8
- package/dest/archiver/archiver_store.d.ts.map +1 -1
- package/dest/archiver/archiver_store_test_suite.d.ts +1 -1
- package/dest/archiver/archiver_store_test_suite.d.ts.map +1 -1
- package/dest/archiver/archiver_store_test_suite.js +54 -53
- package/dest/archiver/data_retrieval.d.ts +2 -2
- package/dest/archiver/data_retrieval.d.ts.map +1 -1
- package/dest/archiver/data_retrieval.js +7 -6
- package/dest/archiver/kv_archiver_store/block_store.d.ts +2 -2
- package/dest/archiver/kv_archiver_store/block_store.d.ts.map +1 -1
- package/dest/archiver/kv_archiver_store/block_store.js +1 -1
- package/dest/archiver/kv_archiver_store/contract_class_store.d.ts +2 -2
- package/dest/archiver/kv_archiver_store/contract_class_store.d.ts.map +1 -1
- package/dest/archiver/kv_archiver_store/contract_class_store.js +1 -1
- package/dest/archiver/kv_archiver_store/contract_instance_store.d.ts +2 -2
- package/dest/archiver/kv_archiver_store/contract_instance_store.d.ts.map +1 -1
- package/dest/archiver/kv_archiver_store/kv_archiver_store.d.ts +7 -7
- package/dest/archiver/kv_archiver_store/kv_archiver_store.d.ts.map +1 -1
- package/dest/archiver/kv_archiver_store/kv_archiver_store.js +6 -6
- package/dest/archiver/kv_archiver_store/log_store.d.ts +2 -2
- package/dest/archiver/kv_archiver_store/log_store.d.ts.map +1 -1
- package/dest/archiver/kv_archiver_store/message_store.d.ts +5 -4
- package/dest/archiver/kv_archiver_store/message_store.d.ts.map +1 -1
- package/dest/archiver/kv_archiver_store/message_store.js +15 -14
- package/dest/archiver/structs/inbox_message.d.ts +4 -4
- package/dest/archiver/structs/inbox_message.d.ts.map +1 -1
- package/dest/archiver/structs/inbox_message.js +6 -6
- package/dest/test/mock_archiver.d.ts +4 -5
- package/dest/test/mock_archiver.d.ts.map +1 -1
- package/dest/test/mock_archiver.js +5 -9
- package/dest/test/mock_l1_to_l2_message_source.d.ts +5 -6
- package/dest/test/mock_l1_to_l2_message_source.d.ts.map +1 -1
- package/dest/test/mock_l1_to_l2_message_source.js +7 -11
- package/dest/test/mock_l2_block_source.d.ts +2 -2
- package/dest/test/mock_l2_block_source.d.ts.map +1 -1
- package/dest/test/mock_l2_block_source.js +1 -1
- package/dest/test/mock_structs.d.ts +3 -2
- package/dest/test/mock_structs.d.ts.map +1 -1
- package/dest/test/mock_structs.js +9 -9
- package/package.json +13 -13
- package/src/archiver/archiver.ts +34 -20
- package/src/archiver/archiver_store.ts +7 -7
- package/src/archiver/archiver_store_test_suite.ts +63 -55
- package/src/archiver/data_retrieval.ts +7 -6
- package/src/archiver/kv_archiver_store/block_store.ts +1 -1
- package/src/archiver/kv_archiver_store/contract_class_store.ts +1 -1
- package/src/archiver/kv_archiver_store/contract_instance_store.ts +1 -1
- package/src/archiver/kv_archiver_store/kv_archiver_store.ts +8 -8
- package/src/archiver/kv_archiver_store/log_store.ts +1 -1
- package/src/archiver/kv_archiver_store/message_store.ts +20 -17
- package/src/archiver/structs/inbox_message.ts +7 -8
- package/src/test/mock_archiver.ts +6 -11
- package/src/test/mock_l1_to_l2_message_source.ts +6 -11
- package/src/test/mock_l2_block_source.ts +1 -1
- package/src/test/mock_structs.ts +10 -10
package/src/archiver/archiver.ts
CHANGED
|
@@ -13,8 +13,8 @@ import { maxBigint } from '@aztec/foundation/bigint';
|
|
|
13
13
|
import { BlockNumber, CheckpointNumber, EpochNumber, SlotNumber } from '@aztec/foundation/branded-types';
|
|
14
14
|
import { Buffer16, Buffer32 } from '@aztec/foundation/buffer';
|
|
15
15
|
import { merge, pick } from '@aztec/foundation/collection';
|
|
16
|
+
import { Fr } from '@aztec/foundation/curves/bn254';
|
|
16
17
|
import type { EthAddress } from '@aztec/foundation/eth-address';
|
|
17
|
-
import { Fr } from '@aztec/foundation/fields';
|
|
18
18
|
import { type Logger, createLogger } from '@aztec/foundation/log';
|
|
19
19
|
import { type PromiseWithResolvers, promiseWithResolvers } from '@aztec/foundation/promise';
|
|
20
20
|
import { RunningPromise, makeLoggingErrorHandler } from '@aztec/foundation/running-promise';
|
|
@@ -63,7 +63,7 @@ import {
|
|
|
63
63
|
import type { GetContractClassLogsResponse, GetPublicLogsResponse } from '@aztec/stdlib/interfaces/client';
|
|
64
64
|
import type { L2LogsSource } from '@aztec/stdlib/interfaces/server';
|
|
65
65
|
import { ContractClassLog, type LogFilter, type PrivateLog, type PublicLog, TxScopedL2Log } from '@aztec/stdlib/logs';
|
|
66
|
-
import type
|
|
66
|
+
import { type L1ToL2MessageSource, computeInHashFromL1ToL2Messages } from '@aztec/stdlib/messaging';
|
|
67
67
|
import type { CheckpointHeader } from '@aztec/stdlib/rollup';
|
|
68
68
|
import { type BlockHeader, type IndexedTxEffect, TxHash, TxReceipt } from '@aztec/stdlib/tx';
|
|
69
69
|
import type { UInt64 } from '@aztec/stdlib/types';
|
|
@@ -594,7 +594,7 @@ export class Archiver extends (EventEmitter as new () => ArchiverEmitter) implem
|
|
|
594
594
|
// Log stats for messages retrieved (if any).
|
|
595
595
|
if (messageCount > 0) {
|
|
596
596
|
this.log.info(
|
|
597
|
-
`Retrieved ${messageCount} new L1 to L2 messages up to message with index ${lastMessage?.index} for
|
|
597
|
+
`Retrieved ${messageCount} new L1 to L2 messages up to message with index ${lastMessage?.index} for checkpoint ${lastMessage?.checkpointNumber}`,
|
|
598
598
|
{ lastMessage, messageCount },
|
|
599
599
|
);
|
|
600
600
|
}
|
|
@@ -916,6 +916,25 @@ export class Archiver extends (EventEmitter as new () => ArchiverEmitter) implem
|
|
|
916
916
|
continue;
|
|
917
917
|
}
|
|
918
918
|
|
|
919
|
+
// Check the inHash of the checkpoint against the l1->l2 messages.
|
|
920
|
+
// The messages should've been synced up to the currentL1BlockNumber and must be available for the published
|
|
921
|
+
// checkpoints we just retrieved.
|
|
922
|
+
const l1ToL2Messages = await this.getL1ToL2Messages(published.checkpoint.number);
|
|
923
|
+
const computedInHash = computeInHashFromL1ToL2Messages(l1ToL2Messages);
|
|
924
|
+
const publishedInHash = published.checkpoint.header.contentCommitment.inHash;
|
|
925
|
+
if (!computedInHash.equals(publishedInHash)) {
|
|
926
|
+
this.log.fatal(`Mismatch inHash for checkpoint ${published.checkpoint.number}`, {
|
|
927
|
+
checkpointHash: published.checkpoint.hash(),
|
|
928
|
+
l1BlockNumber: published.l1.blockNumber,
|
|
929
|
+
computedInHash,
|
|
930
|
+
publishedInHash,
|
|
931
|
+
});
|
|
932
|
+
// Throwing an error since this is most likely caused by a bug.
|
|
933
|
+
throw new Error(
|
|
934
|
+
`Mismatch inHash for checkpoint ${published.checkpoint.number}. Expected ${computedInHash} but got ${publishedInHash}`,
|
|
935
|
+
);
|
|
936
|
+
}
|
|
937
|
+
|
|
919
938
|
validCheckpoints.push(published);
|
|
920
939
|
this.log.debug(
|
|
921
940
|
`Ingesting new checkpoint ${published.checkpoint.number} with ${published.checkpoint.blocks.length} blocks`,
|
|
@@ -969,7 +988,7 @@ export class Archiver extends (EventEmitter as new () => ArchiverEmitter) implem
|
|
|
969
988
|
});
|
|
970
989
|
}
|
|
971
990
|
lastRetrievedCheckpoint = validCheckpoints.at(-1) ?? lastRetrievedCheckpoint;
|
|
972
|
-
lastL1BlockWithCheckpoint =
|
|
991
|
+
lastL1BlockWithCheckpoint = retrievedCheckpoints.at(-1)?.l1.blockNumber ?? lastL1BlockWithCheckpoint;
|
|
973
992
|
} while (searchEndBlock < currentL1BlockNumber);
|
|
974
993
|
|
|
975
994
|
// Important that we update AFTER inserting the blocks.
|
|
@@ -1247,12 +1266,6 @@ export class Archiver extends (EventEmitter as new () => ArchiverEmitter) implem
|
|
|
1247
1266
|
return blocks.map(b => b.toCheckpoint());
|
|
1248
1267
|
}
|
|
1249
1268
|
|
|
1250
|
-
public getL1ToL2MessagesForCheckpoint(checkpointNumber: CheckpointNumber): Promise<Fr[]> {
|
|
1251
|
-
// TODO: Create dedicated api for checkpoints.
|
|
1252
|
-
// This only works when we have one block per checkpoint.
|
|
1253
|
-
return this.getL1ToL2Messages(BlockNumber.fromCheckpointNumber(checkpointNumber));
|
|
1254
|
-
}
|
|
1255
|
-
|
|
1256
1269
|
/**
|
|
1257
1270
|
* Gets up to `limit` amount of L2 blocks starting from `from`.
|
|
1258
1271
|
* @param from - Number of the first block to return (inclusive).
|
|
@@ -1404,12 +1417,12 @@ export class Archiver extends (EventEmitter as new () => ArchiverEmitter) implem
|
|
|
1404
1417
|
}
|
|
1405
1418
|
|
|
1406
1419
|
/**
|
|
1407
|
-
* Gets L1 to L2 message (to be) included in a given
|
|
1408
|
-
* @param
|
|
1420
|
+
* Gets L1 to L2 message (to be) included in a given checkpoint.
|
|
1421
|
+
* @param checkpointNumber - Checkpoint number to get messages for.
|
|
1409
1422
|
* @returns The L1 to L2 messages/leaves of the messages subtree (throws if not found).
|
|
1410
1423
|
*/
|
|
1411
|
-
getL1ToL2Messages(
|
|
1412
|
-
return this.store.getL1ToL2Messages(
|
|
1424
|
+
getL1ToL2Messages(checkpointNumber: CheckpointNumber): Promise<Fr[]> {
|
|
1425
|
+
return this.store.getL1ToL2Messages(checkpointNumber);
|
|
1413
1426
|
}
|
|
1414
1427
|
|
|
1415
1428
|
/**
|
|
@@ -1500,11 +1513,12 @@ export class Archiver extends (EventEmitter as new () => ArchiverEmitter) implem
|
|
|
1500
1513
|
throw new Error(`Target L2 block ${targetL2BlockNumber} not found`);
|
|
1501
1514
|
}
|
|
1502
1515
|
const targetL1BlockNumber = targetL2Block.l1.blockNumber;
|
|
1516
|
+
const targetCheckpointNumber = CheckpointNumber.fromBlockNumber(targetL2BlockNumber);
|
|
1503
1517
|
const targetL1BlockHash = await this.getL1BlockHash(targetL1BlockNumber);
|
|
1504
1518
|
this.log.info(`Unwinding ${blocksToUnwind} blocks from L2 block ${currentL2Block}`);
|
|
1505
1519
|
await this.store.unwindBlocks(BlockNumber(currentL2Block), blocksToUnwind);
|
|
1506
|
-
this.log.info(`Unwinding L1 to L2 messages to ${
|
|
1507
|
-
await this.store.
|
|
1520
|
+
this.log.info(`Unwinding L1 to L2 messages to checkpoint ${targetCheckpointNumber}`);
|
|
1521
|
+
await this.store.rollbackL1ToL2MessagesToCheckpoint(targetCheckpointNumber);
|
|
1508
1522
|
this.log.info(`Setting L1 syncpoints to ${targetL1BlockNumber}`);
|
|
1509
1523
|
await this.store.setBlockSynchedL1BlockNumber(targetL1BlockNumber);
|
|
1510
1524
|
await this.store.setMessageSynchedL1Block({ l1BlockNumber: targetL1BlockNumber, l1BlockHash: targetL1BlockHash });
|
|
@@ -1798,8 +1812,8 @@ export class ArchiverStoreHelper
|
|
|
1798
1812
|
addL1ToL2Messages(messages: InboxMessage[]): Promise<void> {
|
|
1799
1813
|
return this.store.addL1ToL2Messages(messages);
|
|
1800
1814
|
}
|
|
1801
|
-
getL1ToL2Messages(
|
|
1802
|
-
return this.store.getL1ToL2Messages(
|
|
1815
|
+
getL1ToL2Messages(checkpointNumber: CheckpointNumber): Promise<Fr[]> {
|
|
1816
|
+
return this.store.getL1ToL2Messages(checkpointNumber);
|
|
1803
1817
|
}
|
|
1804
1818
|
getL1ToL2MessageIndex(l1ToL2Message: Fr): Promise<bigint | undefined> {
|
|
1805
1819
|
return this.store.getL1ToL2MessageIndex(l1ToL2Message);
|
|
@@ -1858,8 +1872,8 @@ export class ArchiverStoreHelper
|
|
|
1858
1872
|
estimateSize(): Promise<{ mappingSize: number; physicalFileSize: number; actualSize: number; numItems: number }> {
|
|
1859
1873
|
return this.store.estimateSize();
|
|
1860
1874
|
}
|
|
1861
|
-
|
|
1862
|
-
return this.store.
|
|
1875
|
+
rollbackL1ToL2MessagesToCheckpoint(targetCheckpointNumber: CheckpointNumber): Promise<void> {
|
|
1876
|
+
return this.store.rollbackL1ToL2MessagesToCheckpoint(targetCheckpointNumber);
|
|
1863
1877
|
}
|
|
1864
1878
|
iterateL1ToL2Messages(range: CustomRange<bigint> = {}): AsyncIterableIterator<InboxMessage> {
|
|
1865
1879
|
return this.store.iterateL1ToL2Messages(range);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { L1BlockId } from '@aztec/ethereum';
|
|
2
|
-
import { BlockNumber } from '@aztec/foundation/branded-types';
|
|
3
|
-
import type { Fr } from '@aztec/foundation/
|
|
2
|
+
import { BlockNumber, CheckpointNumber } from '@aztec/foundation/branded-types';
|
|
3
|
+
import type { Fr } from '@aztec/foundation/curves/bn254';
|
|
4
4
|
import type { CustomRange } from '@aztec/kv-store';
|
|
5
5
|
import type { FunctionSelector } from '@aztec/stdlib/abi';
|
|
6
6
|
import type { AztecAddress } from '@aztec/stdlib/aztec-address';
|
|
@@ -132,11 +132,11 @@ export interface ArchiverDataStore {
|
|
|
132
132
|
addL1ToL2Messages(messages: InboxMessage[]): Promise<void>;
|
|
133
133
|
|
|
134
134
|
/**
|
|
135
|
-
* Gets L1 to L2 message (to be) included in a given
|
|
136
|
-
* @param
|
|
135
|
+
* Gets L1 to L2 message (to be) included in a given checkpoint.
|
|
136
|
+
* @param checkpointNumber - Checkpoint number to get messages for.
|
|
137
137
|
* @returns The L1 to L2 messages/leaves of the messages subtree (throws if not found).
|
|
138
138
|
*/
|
|
139
|
-
getL1ToL2Messages(
|
|
139
|
+
getL1ToL2Messages(checkpointNumber: CheckpointNumber): Promise<Fr[]>;
|
|
140
140
|
|
|
141
141
|
/**
|
|
142
142
|
* Gets the L1 to L2 message index in the L1 to L2 message tree.
|
|
@@ -290,8 +290,8 @@ export interface ArchiverDataStore {
|
|
|
290
290
|
/** Closes the underlying data store. */
|
|
291
291
|
close(): Promise<void>;
|
|
292
292
|
|
|
293
|
-
/** Deletes all L1 to L2 messages up until (excluding) the target
|
|
294
|
-
|
|
293
|
+
/** Deletes all L1 to L2 messages up until (excluding) the target checkpoint number. */
|
|
294
|
+
rollbackL1ToL2MessagesToCheckpoint(targetCheckpointNumber: CheckpointNumber): Promise<void>;
|
|
295
295
|
|
|
296
296
|
/** Returns an async iterator to all L1 to L2 messages on the range. */
|
|
297
297
|
iterateL1ToL2Messages(range?: CustomRange<bigint>): AsyncIterableIterator<InboxMessage>;
|
|
@@ -4,11 +4,11 @@ import {
|
|
|
4
4
|
PRIVATE_LOG_SIZE_IN_FIELDS,
|
|
5
5
|
} from '@aztec/constants';
|
|
6
6
|
import { makeTuple } from '@aztec/foundation/array';
|
|
7
|
-
import { BlockNumber, EpochNumber } from '@aztec/foundation/branded-types';
|
|
7
|
+
import { BlockNumber, CheckpointNumber, EpochNumber } from '@aztec/foundation/branded-types';
|
|
8
8
|
import { Buffer16, Buffer32 } from '@aztec/foundation/buffer';
|
|
9
9
|
import { times, timesParallel } from '@aztec/foundation/collection';
|
|
10
|
-
import { randomInt } from '@aztec/foundation/crypto';
|
|
11
|
-
import { Fr } from '@aztec/foundation/
|
|
10
|
+
import { randomInt } from '@aztec/foundation/crypto/random';
|
|
11
|
+
import { Fr } from '@aztec/foundation/curves/bn254';
|
|
12
12
|
import { toArray } from '@aztec/foundation/iterable';
|
|
13
13
|
import { sleep } from '@aztec/foundation/sleep';
|
|
14
14
|
import { AztecAddress } from '@aztec/stdlib/aztec-address';
|
|
@@ -20,7 +20,7 @@ import {
|
|
|
20
20
|
PublishedL2Block,
|
|
21
21
|
type ValidateBlockResult,
|
|
22
22
|
randomBlockInfo,
|
|
23
|
-
|
|
23
|
+
wrapDataInBlock,
|
|
24
24
|
} from '@aztec/stdlib/block';
|
|
25
25
|
import {
|
|
26
26
|
type ContractClassPublic,
|
|
@@ -413,11 +413,11 @@ export function describeArchiverDataStore(
|
|
|
413
413
|
});
|
|
414
414
|
|
|
415
415
|
it.each([
|
|
416
|
-
() =>
|
|
417
|
-
() =>
|
|
418
|
-
() =>
|
|
419
|
-
() =>
|
|
420
|
-
() =>
|
|
416
|
+
() => wrapDataInBlock(blocks[0].block.body.txEffects[0], blocks[0].block),
|
|
417
|
+
() => wrapDataInBlock(blocks[9].block.body.txEffects[3], blocks[9].block),
|
|
418
|
+
() => wrapDataInBlock(blocks[3].block.body.txEffects[1], blocks[3].block),
|
|
419
|
+
() => wrapDataInBlock(blocks[5].block.body.txEffects[2], blocks[5].block),
|
|
420
|
+
() => wrapDataInBlock(blocks[1].block.body.txEffects[0], blocks[1].block),
|
|
421
421
|
])('tries to retrieves a previously stored transaction after deleted', async getExpectedTx => {
|
|
422
422
|
await store.unwindBlocks(BlockNumber(blocks.length), blocks.length);
|
|
423
423
|
|
|
@@ -431,7 +431,7 @@ export function describeArchiverDataStore(
|
|
|
431
431
|
});
|
|
432
432
|
|
|
433
433
|
it('does not fail if the block is unwound while requesting a tx', async () => {
|
|
434
|
-
const expectedTx = await
|
|
434
|
+
const expectedTx = await wrapDataInBlock(blocks[1].block.body.txEffects[0], blocks[1].block);
|
|
435
435
|
let done = false;
|
|
436
436
|
void (async () => {
|
|
437
437
|
while (!done) {
|
|
@@ -446,7 +446,7 @@ export function describeArchiverDataStore(
|
|
|
446
446
|
});
|
|
447
447
|
|
|
448
448
|
describe('L1 to L2 Messages', () => {
|
|
449
|
-
const
|
|
449
|
+
const initialCheckpointNumber = CheckpointNumber(13);
|
|
450
450
|
|
|
451
451
|
const checkMessages = async (msgs: InboxMessage[]) => {
|
|
452
452
|
expect(await store.getLastL1ToL2Message()).toEqual(msgs.at(-1));
|
|
@@ -454,46 +454,50 @@ export function describeArchiverDataStore(
|
|
|
454
454
|
expect(await store.getTotalL1ToL2MessageCount()).toEqual(BigInt(msgs.length));
|
|
455
455
|
};
|
|
456
456
|
|
|
457
|
-
const makeInboxMessagesWithFullBlocks = (
|
|
457
|
+
const makeInboxMessagesWithFullBlocks = (
|
|
458
|
+
blockCount: number,
|
|
459
|
+
opts: { initialCheckpointNumber?: CheckpointNumber } = {},
|
|
460
|
+
) =>
|
|
458
461
|
makeInboxMessages(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP * blockCount, {
|
|
459
462
|
overrideFn: (msg, i) => {
|
|
460
|
-
const
|
|
461
|
-
(opts.
|
|
463
|
+
const checkpointNumber = CheckpointNumber(
|
|
464
|
+
(opts.initialCheckpointNumber ?? initialCheckpointNumber) +
|
|
465
|
+
Math.floor(i / NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP),
|
|
462
466
|
);
|
|
463
467
|
const index =
|
|
464
|
-
InboxLeaf.
|
|
465
|
-
return { ...msg,
|
|
468
|
+
InboxLeaf.smallestIndexForCheckpoint(checkpointNumber) + BigInt(i % NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP);
|
|
469
|
+
return { ...msg, checkpointNumber, index };
|
|
466
470
|
},
|
|
467
471
|
});
|
|
468
472
|
|
|
469
473
|
it('stores first message ever', async () => {
|
|
470
|
-
const msg = makeInboxMessage(Buffer16.ZERO, { index: 0n,
|
|
474
|
+
const msg = makeInboxMessage(Buffer16.ZERO, { index: 0n, checkpointNumber: CheckpointNumber(1) });
|
|
471
475
|
await store.addL1ToL2Messages([msg]);
|
|
472
476
|
|
|
473
477
|
await checkMessages([msg]);
|
|
474
|
-
expect(await store.getL1ToL2Messages(
|
|
478
|
+
expect(await store.getL1ToL2Messages(CheckpointNumber(1))).toEqual([msg.leaf]);
|
|
475
479
|
});
|
|
476
480
|
|
|
477
481
|
it('stores single message', async () => {
|
|
478
|
-
const msg = makeInboxMessage(Buffer16.ZERO, {
|
|
482
|
+
const msg = makeInboxMessage(Buffer16.ZERO, { checkpointNumber: CheckpointNumber(2) });
|
|
479
483
|
await store.addL1ToL2Messages([msg]);
|
|
480
484
|
|
|
481
485
|
await checkMessages([msg]);
|
|
482
|
-
expect(await store.getL1ToL2Messages(
|
|
486
|
+
expect(await store.getL1ToL2Messages(CheckpointNumber(2))).toEqual([msg.leaf]);
|
|
483
487
|
});
|
|
484
488
|
|
|
485
489
|
it('stores and returns messages across different blocks', async () => {
|
|
486
|
-
const msgs = makeInboxMessages(5, {
|
|
490
|
+
const msgs = makeInboxMessages(5, { initialCheckpointNumber });
|
|
487
491
|
await store.addL1ToL2Messages(msgs);
|
|
488
492
|
|
|
489
493
|
await checkMessages(msgs);
|
|
490
|
-
expect(await store.getL1ToL2Messages(
|
|
494
|
+
expect(await store.getL1ToL2Messages(CheckpointNumber(initialCheckpointNumber + 2))).toEqual(
|
|
491
495
|
[msgs[2]].map(m => m.leaf),
|
|
492
496
|
);
|
|
493
497
|
});
|
|
494
498
|
|
|
495
499
|
it('stores the same messages again', async () => {
|
|
496
|
-
const msgs = makeInboxMessages(5, {
|
|
500
|
+
const msgs = makeInboxMessages(5, { initialCheckpointNumber });
|
|
497
501
|
await store.addL1ToL2Messages(msgs);
|
|
498
502
|
await store.addL1ToL2Messages(msgs.slice(2));
|
|
499
503
|
|
|
@@ -501,26 +505,29 @@ export function describeArchiverDataStore(
|
|
|
501
505
|
});
|
|
502
506
|
|
|
503
507
|
it('stores and returns messages across different blocks with gaps', async () => {
|
|
504
|
-
const msgs1 = makeInboxMessages(3, {
|
|
505
|
-
const msgs2 = makeInboxMessages(3, {
|
|
508
|
+
const msgs1 = makeInboxMessages(3, { initialCheckpointNumber: CheckpointNumber(1) });
|
|
509
|
+
const msgs2 = makeInboxMessages(3, {
|
|
510
|
+
initialCheckpointNumber: CheckpointNumber(20),
|
|
511
|
+
initialHash: msgs1.at(-1)!.rollingHash,
|
|
512
|
+
});
|
|
506
513
|
|
|
507
514
|
await store.addL1ToL2Messages(msgs1);
|
|
508
515
|
await store.addL1ToL2Messages(msgs2);
|
|
509
516
|
|
|
510
517
|
await checkMessages([...msgs1, ...msgs2]);
|
|
511
518
|
|
|
512
|
-
expect(await store.getL1ToL2Messages(
|
|
513
|
-
expect(await store.getL1ToL2Messages(
|
|
514
|
-
expect(await store.getL1ToL2Messages(
|
|
515
|
-
expect(await store.getL1ToL2Messages(
|
|
519
|
+
expect(await store.getL1ToL2Messages(CheckpointNumber(1))).toEqual([msgs1[0].leaf]);
|
|
520
|
+
expect(await store.getL1ToL2Messages(CheckpointNumber(4))).toEqual([]);
|
|
521
|
+
expect(await store.getL1ToL2Messages(CheckpointNumber(20))).toEqual([msgs2[0].leaf]);
|
|
522
|
+
expect(await store.getL1ToL2Messages(CheckpointNumber(24))).toEqual([]);
|
|
516
523
|
});
|
|
517
524
|
|
|
518
525
|
it('stores and returns messages with block numbers larger than a byte', async () => {
|
|
519
|
-
const msgs = makeInboxMessages(5, {
|
|
526
|
+
const msgs = makeInboxMessages(5, { initialCheckpointNumber: CheckpointNumber(1000) });
|
|
520
527
|
await store.addL1ToL2Messages(msgs);
|
|
521
528
|
|
|
522
529
|
await checkMessages(msgs);
|
|
523
|
-
expect(await store.getL1ToL2Messages(
|
|
530
|
+
expect(await store.getL1ToL2Messages(CheckpointNumber(1002))).toEqual([msgs[2]].map(m => m.leaf));
|
|
524
531
|
});
|
|
525
532
|
|
|
526
533
|
it('stores and returns multiple messages per block', async () => {
|
|
@@ -528,7 +535,7 @@ export function describeArchiverDataStore(
|
|
|
528
535
|
await store.addL1ToL2Messages(msgs);
|
|
529
536
|
|
|
530
537
|
await checkMessages(msgs);
|
|
531
|
-
const blockMessages = await store.getL1ToL2Messages(
|
|
538
|
+
const blockMessages = await store.getL1ToL2Messages(CheckpointNumber(initialCheckpointNumber + 1));
|
|
532
539
|
expect(blockMessages).toHaveLength(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP);
|
|
533
540
|
expect(blockMessages).toEqual(
|
|
534
541
|
msgs.slice(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP, NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP * 2).map(m => m.leaf),
|
|
@@ -536,21 +543,21 @@ export function describeArchiverDataStore(
|
|
|
536
543
|
});
|
|
537
544
|
|
|
538
545
|
it('stores messages in multiple operations', async () => {
|
|
539
|
-
const msgs = makeInboxMessages(20, {
|
|
546
|
+
const msgs = makeInboxMessages(20, { initialCheckpointNumber });
|
|
540
547
|
await store.addL1ToL2Messages(msgs.slice(0, 10));
|
|
541
548
|
await store.addL1ToL2Messages(msgs.slice(10, 20));
|
|
542
549
|
|
|
543
|
-
expect(await store.getL1ToL2Messages(
|
|
550
|
+
expect(await store.getL1ToL2Messages(CheckpointNumber(initialCheckpointNumber + 2))).toEqual(
|
|
544
551
|
[msgs[2]].map(m => m.leaf),
|
|
545
552
|
);
|
|
546
|
-
expect(await store.getL1ToL2Messages(
|
|
553
|
+
expect(await store.getL1ToL2Messages(CheckpointNumber(initialCheckpointNumber + 12))).toEqual(
|
|
547
554
|
[msgs[12]].map(m => m.leaf),
|
|
548
555
|
);
|
|
549
556
|
await checkMessages(msgs);
|
|
550
557
|
});
|
|
551
558
|
|
|
552
559
|
it('iterates over messages from start index', async () => {
|
|
553
|
-
const msgs = makeInboxMessages(10, {
|
|
560
|
+
const msgs = makeInboxMessages(10, { initialCheckpointNumber });
|
|
554
561
|
await store.addL1ToL2Messages(msgs);
|
|
555
562
|
|
|
556
563
|
const iterated = await toArray(store.iterateL1ToL2Messages({ start: msgs[3].index }));
|
|
@@ -558,8 +565,9 @@ export function describeArchiverDataStore(
|
|
|
558
565
|
});
|
|
559
566
|
|
|
560
567
|
it('iterates over messages in reverse', async () => {
|
|
561
|
-
const msgs = makeInboxMessages(10, {
|
|
568
|
+
const msgs = makeInboxMessages(10, { initialCheckpointNumber });
|
|
562
569
|
await store.addL1ToL2Messages(msgs);
|
|
570
|
+
initialCheckpointNumber;
|
|
563
571
|
|
|
564
572
|
const iterated = await toArray(store.iterateL1ToL2Messages({ reverse: true, end: msgs[3].index }));
|
|
565
573
|
expect(iterated).toEqual(msgs.slice(0, 4).reverse());
|
|
@@ -571,8 +579,8 @@ export function describeArchiverDataStore(
|
|
|
571
579
|
});
|
|
572
580
|
|
|
573
581
|
it('throws if block number for the first message is out of order', async () => {
|
|
574
|
-
const msgs = makeInboxMessages(4, {
|
|
575
|
-
msgs[2].
|
|
582
|
+
const msgs = makeInboxMessages(4, { initialCheckpointNumber });
|
|
583
|
+
msgs[2].checkpointNumber = CheckpointNumber(initialCheckpointNumber - 1);
|
|
576
584
|
await store.addL1ToL2Messages(msgs.slice(0, 2));
|
|
577
585
|
await expect(store.addL1ToL2Messages(msgs.slice(2, 4))).rejects.toThrow(MessageStoreError);
|
|
578
586
|
});
|
|
@@ -586,28 +594,28 @@ export function describeArchiverDataStore(
|
|
|
586
594
|
it('throws if rolling hash for first message is not correct', async () => {
|
|
587
595
|
const msgs = makeInboxMessages(4);
|
|
588
596
|
msgs[2].rollingHash = Buffer16.random();
|
|
589
|
-
await store.addL1ToL2Messages(msgs.slice(0,
|
|
597
|
+
await store.addL1ToL2Messages(msgs.slice(0, CheckpointNumber(2)));
|
|
590
598
|
await expect(store.addL1ToL2Messages(msgs.slice(2, 4))).rejects.toThrow(MessageStoreError);
|
|
591
599
|
});
|
|
592
600
|
|
|
593
601
|
it('throws if index is not in the correct range', async () => {
|
|
594
|
-
const msgs = makeInboxMessages(5, {
|
|
602
|
+
const msgs = makeInboxMessages(5, { initialCheckpointNumber });
|
|
595
603
|
msgs.at(-1)!.index += 100n;
|
|
596
604
|
await expect(store.addL1ToL2Messages(msgs)).rejects.toThrow(MessageStoreError);
|
|
597
605
|
});
|
|
598
606
|
|
|
599
607
|
it('throws if first index in block has gaps', async () => {
|
|
600
|
-
const msgs = makeInboxMessages(4, {
|
|
608
|
+
const msgs = makeInboxMessages(4, { initialCheckpointNumber });
|
|
601
609
|
msgs[2].index++;
|
|
602
610
|
await expect(store.addL1ToL2Messages(msgs)).rejects.toThrow(MessageStoreError);
|
|
603
611
|
});
|
|
604
612
|
|
|
605
613
|
it('throws if index does not follow previous one', async () => {
|
|
606
614
|
const msgs = makeInboxMessages(2, {
|
|
607
|
-
|
|
615
|
+
initialCheckpointNumber,
|
|
608
616
|
overrideFn: (msg, i) => ({
|
|
609
617
|
...msg,
|
|
610
|
-
|
|
618
|
+
checkpointNumber: CheckpointNumber(2),
|
|
611
619
|
index: BigInt(i + NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP * 2),
|
|
612
620
|
}),
|
|
613
621
|
});
|
|
@@ -616,28 +624,28 @@ export function describeArchiverDataStore(
|
|
|
616
624
|
});
|
|
617
625
|
|
|
618
626
|
it('removes messages up to the given block number', async () => {
|
|
619
|
-
const msgs = makeInboxMessagesWithFullBlocks(4, {
|
|
627
|
+
const msgs = makeInboxMessagesWithFullBlocks(4, { initialCheckpointNumber: CheckpointNumber(1) });
|
|
620
628
|
|
|
621
629
|
await store.addL1ToL2Messages(msgs);
|
|
622
630
|
await checkMessages(msgs);
|
|
623
631
|
|
|
624
|
-
expect(await store.getL1ToL2Messages(
|
|
625
|
-
expect(await store.getL1ToL2Messages(
|
|
626
|
-
expect(await store.getL1ToL2Messages(
|
|
627
|
-
expect(await store.getL1ToL2Messages(
|
|
632
|
+
expect(await store.getL1ToL2Messages(CheckpointNumber(1))).toHaveLength(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP);
|
|
633
|
+
expect(await store.getL1ToL2Messages(CheckpointNumber(2))).toHaveLength(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP);
|
|
634
|
+
expect(await store.getL1ToL2Messages(CheckpointNumber(3))).toHaveLength(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP);
|
|
635
|
+
expect(await store.getL1ToL2Messages(CheckpointNumber(4))).toHaveLength(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP);
|
|
628
636
|
|
|
629
|
-
await store.
|
|
637
|
+
await store.rollbackL1ToL2MessagesToCheckpoint(CheckpointNumber(2));
|
|
630
638
|
|
|
631
|
-
expect(await store.getL1ToL2Messages(
|
|
632
|
-
expect(await store.getL1ToL2Messages(
|
|
633
|
-
expect(await store.getL1ToL2Messages(
|
|
634
|
-
expect(await store.getL1ToL2Messages(
|
|
639
|
+
expect(await store.getL1ToL2Messages(CheckpointNumber(1))).toHaveLength(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP);
|
|
640
|
+
expect(await store.getL1ToL2Messages(CheckpointNumber(2))).toHaveLength(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP);
|
|
641
|
+
expect(await store.getL1ToL2Messages(CheckpointNumber(3))).toHaveLength(0);
|
|
642
|
+
expect(await store.getL1ToL2Messages(CheckpointNumber(4))).toHaveLength(0);
|
|
635
643
|
|
|
636
644
|
await checkMessages(msgs.slice(0, NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP * 2));
|
|
637
645
|
});
|
|
638
646
|
|
|
639
647
|
it('removes messages starting with the given index', async () => {
|
|
640
|
-
const msgs = makeInboxMessagesWithFullBlocks(4, {
|
|
648
|
+
const msgs = makeInboxMessagesWithFullBlocks(4, { initialCheckpointNumber: CheckpointNumber(1) });
|
|
641
649
|
await store.addL1ToL2Messages(msgs);
|
|
642
650
|
|
|
643
651
|
await store.removeL1ToL2Messages(msgs[13].index);
|
|
@@ -14,11 +14,11 @@ import type {
|
|
|
14
14
|
ViemPublicClient,
|
|
15
15
|
} from '@aztec/ethereum';
|
|
16
16
|
import { asyncPool } from '@aztec/foundation/async-pool';
|
|
17
|
-
import {
|
|
17
|
+
import { CheckpointNumber } from '@aztec/foundation/branded-types';
|
|
18
18
|
import { Buffer16, Buffer32 } from '@aztec/foundation/buffer';
|
|
19
|
+
import { Fr } from '@aztec/foundation/curves/bn254';
|
|
19
20
|
import type { EthAddress } from '@aztec/foundation/eth-address';
|
|
20
21
|
import type { ViemSignature } from '@aztec/foundation/eth-signature';
|
|
21
|
-
import { Fr } from '@aztec/foundation/fields';
|
|
22
22
|
import { type Logger, createLogger } from '@aztec/foundation/log';
|
|
23
23
|
import { type InboxAbi, RollupAbi } from '@aztec/l1-artifacts';
|
|
24
24
|
import { Body, CommitteeAttestation, L2BlockNew } from '@aztec/stdlib/block';
|
|
@@ -72,8 +72,8 @@ export async function retrievedToPublishedCheckpoint({
|
|
|
72
72
|
.slice(1)
|
|
73
73
|
.concat([archiveRoot]);
|
|
74
74
|
|
|
75
|
-
//
|
|
76
|
-
//
|
|
75
|
+
// An error will be thrown from `decodeCheckpointBlobDataFromBlobs` if it can't read a field for the
|
|
76
|
+
// `l1ToL2MessageRoot` of the first block. So below we can safely assume it exists:
|
|
77
77
|
const l1toL2MessageTreeRoot = blocksBlobData[0].l1ToL2MessageRoot!;
|
|
78
78
|
|
|
79
79
|
const spongeBlob = SpongeBlob.init();
|
|
@@ -127,7 +127,7 @@ export async function retrievedToPublishedCheckpoint({
|
|
|
127
127
|
|
|
128
128
|
const newArchive = new AppendOnlyTreeSnapshot(newArchiveRoots[i], l2BlockNumber + 1);
|
|
129
129
|
|
|
130
|
-
l2Blocks.push(new L2BlockNew(newArchive, header, body));
|
|
130
|
+
l2Blocks.push(new L2BlockNew(newArchive, header, body, checkpointNumber, i));
|
|
131
131
|
}
|
|
132
132
|
|
|
133
133
|
const lastBlock = l2Blocks.at(-1)!;
|
|
@@ -404,6 +404,7 @@ async function getCheckpointFromRollupTx(
|
|
|
404
404
|
} else {
|
|
405
405
|
logger.fatal('Unable to sync: failed to decode fetched blob, this blob was likely not created by us');
|
|
406
406
|
}
|
|
407
|
+
// Throwing an error since this is most likely caused by a bug.
|
|
407
408
|
throw err;
|
|
408
409
|
}
|
|
409
410
|
|
|
@@ -470,7 +471,7 @@ function mapLogsInboxMessage(logs: GetContractEventsReturnType<typeof InboxAbi,
|
|
|
470
471
|
leaf: Fr.fromHexString(hash!),
|
|
471
472
|
l1BlockNumber: log.blockNumber,
|
|
472
473
|
l1BlockHash: Buffer32.fromString(log.blockHash),
|
|
473
|
-
|
|
474
|
+
checkpointNumber: CheckpointNumber.fromBigInt(checkpointNumber!),
|
|
474
475
|
rollingHash: Buffer16.fromString(rollingHash!),
|
|
475
476
|
};
|
|
476
477
|
});
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { INITIAL_L2_BLOCK_NUM } from '@aztec/constants';
|
|
2
2
|
import { BlockNumber } from '@aztec/foundation/branded-types';
|
|
3
|
-
import { Fr } from '@aztec/foundation/
|
|
3
|
+
import { Fr } from '@aztec/foundation/curves/bn254';
|
|
4
4
|
import { toArray } from '@aztec/foundation/iterable';
|
|
5
5
|
import { createLogger } from '@aztec/foundation/log';
|
|
6
6
|
import { BufferReader } from '@aztec/foundation/serialize';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Fr } from '@aztec/foundation/
|
|
1
|
+
import { Fr } from '@aztec/foundation/curves/bn254';
|
|
2
2
|
import { toArray } from '@aztec/foundation/iterable';
|
|
3
3
|
import { BufferReader, numToUInt8, serializeToBuffer } from '@aztec/foundation/serialize';
|
|
4
4
|
import type { AztecAsyncKVStore, AztecAsyncMap } from '@aztec/kv-store';
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { L1BlockId } from '@aztec/ethereum';
|
|
2
|
-
import { BlockNumber } from '@aztec/foundation/branded-types';
|
|
3
|
-
import type { Fr } from '@aztec/foundation/
|
|
2
|
+
import { BlockNumber, CheckpointNumber } from '@aztec/foundation/branded-types';
|
|
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';
|
|
6
6
|
import type { AztecAsyncKVStore, CustomRange, StoreSize } from '@aztec/kv-store';
|
|
@@ -300,12 +300,12 @@ export class KVArchiverDataStore implements ArchiverDataStore, ContractDataSourc
|
|
|
300
300
|
}
|
|
301
301
|
|
|
302
302
|
/**
|
|
303
|
-
* Gets L1 to L2 message (to be) included in a given
|
|
304
|
-
* @param
|
|
303
|
+
* Gets L1 to L2 message (to be) included in a given checkpoint.
|
|
304
|
+
* @param checkpointNumber - Checkpoint number to get messages for.
|
|
305
305
|
* @returns The L1 to L2 messages/leaves of the messages subtree (throws if not found).
|
|
306
306
|
*/
|
|
307
|
-
getL1ToL2Messages(
|
|
308
|
-
return this.#messageStore.getL1ToL2Messages(
|
|
307
|
+
getL1ToL2Messages(checkpointNumber: CheckpointNumber): Promise<Fr[]> {
|
|
308
|
+
return this.#messageStore.getL1ToL2Messages(checkpointNumber);
|
|
309
309
|
}
|
|
310
310
|
|
|
311
311
|
/**
|
|
@@ -401,8 +401,8 @@ export class KVArchiverDataStore implements ArchiverDataStore, ContractDataSourc
|
|
|
401
401
|
return this.db.estimateSize();
|
|
402
402
|
}
|
|
403
403
|
|
|
404
|
-
public
|
|
405
|
-
return this.#messageStore.
|
|
404
|
+
public rollbackL1ToL2MessagesToCheckpoint(targetCheckpointNumber: CheckpointNumber): Promise<void> {
|
|
405
|
+
return this.#messageStore.rollbackL1ToL2MessagesToCheckpoint(targetCheckpointNumber);
|
|
406
406
|
}
|
|
407
407
|
|
|
408
408
|
public iterateL1ToL2Messages(range: CustomRange<bigint> = {}): AsyncIterableIterator<InboxMessage> {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { INITIAL_L2_BLOCK_NUM, MAX_NOTE_HASHES_PER_TX } from '@aztec/constants';
|
|
2
2
|
import { BlockNumber } from '@aztec/foundation/branded-types';
|
|
3
|
-
import type { Fr } from '@aztec/foundation/
|
|
3
|
+
import type { Fr } from '@aztec/foundation/curves/bn254';
|
|
4
4
|
import { createLogger } from '@aztec/foundation/log';
|
|
5
5
|
import { BufferReader, numToUInt32BE } from '@aztec/foundation/serialize';
|
|
6
6
|
import type { AztecAsyncKVStore, AztecAsyncMap } from '@aztec/kv-store';
|