@aztec/archiver 0.0.1-commit.b655e406 → 0.0.1-commit.d3ec352c
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 +53 -40
- package/dest/archiver/archiver.d.ts.map +1 -1
- package/dest/archiver/archiver.js +333 -221
- package/dest/archiver/archiver_store.d.ts +16 -15
- 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 +85 -84
- package/dest/archiver/config.d.ts +1 -1
- package/dest/archiver/config.d.ts.map +1 -1
- package/dest/archiver/config.js +5 -0
- package/dest/archiver/data_retrieval.d.ts +18 -17
- package/dest/archiver/data_retrieval.d.ts.map +1 -1
- package/dest/archiver/data_retrieval.js +111 -86
- package/dest/archiver/errors.d.ts +1 -1
- package/dest/archiver/errors.d.ts.map +1 -1
- package/dest/archiver/index.d.ts +1 -1
- package/dest/archiver/instrumentation.d.ts +3 -3
- package/dest/archiver/instrumentation.d.ts.map +1 -1
- package/dest/archiver/kv_archiver_store/block_store.d.ts +9 -8
- package/dest/archiver/kv_archiver_store/block_store.d.ts.map +1 -1
- package/dest/archiver/kv_archiver_store/block_store.js +8 -7
- package/dest/archiver/kv_archiver_store/contract_class_store.d.ts +1 -1
- package/dest/archiver/kv_archiver_store/contract_class_store.d.ts.map +1 -1
- package/dest/archiver/kv_archiver_store/contract_instance_store.d.ts +1 -1
- 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 +18 -17
- package/dest/archiver/kv_archiver_store/kv_archiver_store.d.ts.map +1 -1
- package/dest/archiver/kv_archiver_store/log_store.d.ts +1 -1
- package/dest/archiver/kv_archiver_store/log_store.d.ts.map +1 -1
- package/dest/archiver/kv_archiver_store/log_store.js +3 -2
- package/dest/archiver/kv_archiver_store/message_store.d.ts +1 -1
- package/dest/archiver/kv_archiver_store/message_store.d.ts.map +1 -1
- package/dest/archiver/structs/data_retrieval.d.ts +1 -1
- package/dest/archiver/structs/inbox_message.d.ts +3 -3
- package/dest/archiver/structs/inbox_message.d.ts.map +1 -1
- package/dest/archiver/structs/inbox_message.js +2 -1
- package/dest/archiver/structs/published.d.ts +3 -2
- package/dest/archiver/structs/published.d.ts.map +1 -1
- package/dest/archiver/validation.d.ts +10 -4
- package/dest/archiver/validation.d.ts.map +1 -1
- package/dest/archiver/validation.js +29 -21
- package/dest/factory.d.ts +1 -1
- package/dest/factory.d.ts.map +1 -1
- package/dest/factory.js +3 -2
- package/dest/index.d.ts +2 -2
- package/dest/index.d.ts.map +1 -1
- package/dest/index.js +1 -1
- package/dest/rpc/index.d.ts +2 -2
- package/dest/test/index.d.ts +1 -1
- package/dest/test/mock_archiver.d.ts +14 -5
- package/dest/test/mock_archiver.d.ts.map +1 -1
- package/dest/test/mock_archiver.js +19 -10
- package/dest/test/mock_l1_to_l2_message_source.d.ts +4 -2
- 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 -2
- package/dest/test/mock_l2_block_source.d.ts +14 -9
- package/dest/test/mock_l2_block_source.d.ts.map +1 -1
- package/dest/test/mock_l2_block_source.js +20 -7
- package/dest/test/mock_structs.d.ts +1 -1
- package/dest/test/mock_structs.d.ts.map +1 -1
- package/dest/test/mock_structs.js +3 -2
- package/package.json +17 -17
- package/src/archiver/archiver.ts +448 -290
- package/src/archiver/archiver_store.ts +19 -14
- package/src/archiver/archiver_store_test_suite.ts +111 -79
- package/src/archiver/config.ts +5 -0
- package/src/archiver/data_retrieval.ts +157 -125
- package/src/archiver/instrumentation.ts +2 -2
- package/src/archiver/kv_archiver_store/block_store.ts +17 -16
- package/src/archiver/kv_archiver_store/kv_archiver_store.ts +16 -15
- package/src/archiver/kv_archiver_store/log_store.ts +3 -2
- package/src/archiver/structs/inbox_message.ts +5 -4
- package/src/archiver/structs/published.ts +2 -1
- package/src/archiver/validation.ts +52 -27
- package/src/factory.ts +3 -2
- package/src/index.ts +1 -1
- package/src/test/mock_archiver.ts +22 -11
- package/src/test/mock_l1_to_l2_message_source.ts +9 -3
- package/src/test/mock_l2_block_source.ts +30 -13
- package/src/test/mock_structs.ts +3 -2
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { L1BlockId } from '@aztec/ethereum';
|
|
2
|
+
import { BlockNumber } from '@aztec/foundation/branded-types';
|
|
2
3
|
import type { Fr } from '@aztec/foundation/fields';
|
|
3
4
|
import { toArray } from '@aztec/foundation/iterable';
|
|
4
5
|
import { createLogger } from '@aztec/foundation/log';
|
|
@@ -65,7 +66,7 @@ export class KVArchiverDataStore implements ArchiverDataStore, ContractDataSourc
|
|
|
65
66
|
return this.db.transactionAsync(callback);
|
|
66
67
|
}
|
|
67
68
|
|
|
68
|
-
public getBlockNumber(): Promise<
|
|
69
|
+
public getBlockNumber(): Promise<BlockNumber> {
|
|
69
70
|
return this.getSynchedL2BlockNumber();
|
|
70
71
|
}
|
|
71
72
|
|
|
@@ -124,7 +125,7 @@ export class KVArchiverDataStore implements ArchiverDataStore, ContractDataSourc
|
|
|
124
125
|
async addContractClasses(
|
|
125
126
|
data: ContractClassPublic[],
|
|
126
127
|
bytecodeCommitments: Fr[],
|
|
127
|
-
blockNumber:
|
|
128
|
+
blockNumber: BlockNumber,
|
|
128
129
|
): Promise<boolean> {
|
|
129
130
|
return (
|
|
130
131
|
await Promise.all(
|
|
@@ -133,7 +134,7 @@ export class KVArchiverDataStore implements ArchiverDataStore, ContractDataSourc
|
|
|
133
134
|
).every(Boolean);
|
|
134
135
|
}
|
|
135
136
|
|
|
136
|
-
async deleteContractClasses(data: ContractClassPublic[], blockNumber:
|
|
137
|
+
async deleteContractClasses(data: ContractClassPublic[], blockNumber: BlockNumber): Promise<boolean> {
|
|
137
138
|
return (await Promise.all(data.map(c => this.#contractClassStore.deleteContractClasses(c, blockNumber)))).every(
|
|
138
139
|
Boolean,
|
|
139
140
|
);
|
|
@@ -151,13 +152,13 @@ export class KVArchiverDataStore implements ArchiverDataStore, ContractDataSourc
|
|
|
151
152
|
return this.#contractClassStore.addFunctions(contractClassId, privateFunctions, utilityFunctions);
|
|
152
153
|
}
|
|
153
154
|
|
|
154
|
-
async addContractInstances(data: ContractInstanceWithAddress[], blockNumber:
|
|
155
|
+
async addContractInstances(data: ContractInstanceWithAddress[], blockNumber: BlockNumber): Promise<boolean> {
|
|
155
156
|
return (await Promise.all(data.map(c => this.#contractInstanceStore.addContractInstance(c, blockNumber)))).every(
|
|
156
157
|
Boolean,
|
|
157
158
|
);
|
|
158
159
|
}
|
|
159
160
|
|
|
160
|
-
async deleteContractInstances(data: ContractInstanceWithAddress[], _blockNumber:
|
|
161
|
+
async deleteContractInstances(data: ContractInstanceWithAddress[], _blockNumber: BlockNumber): Promise<boolean> {
|
|
161
162
|
return (await Promise.all(data.map(c => this.#contractInstanceStore.deleteContractInstance(c)))).every(Boolean);
|
|
162
163
|
}
|
|
163
164
|
|
|
@@ -196,11 +197,11 @@ export class KVArchiverDataStore implements ArchiverDataStore, ContractDataSourc
|
|
|
196
197
|
* @param blocksToUnwind - The number of blocks we are to unwind
|
|
197
198
|
* @returns True if the operation is successful
|
|
198
199
|
*/
|
|
199
|
-
unwindBlocks(from:
|
|
200
|
+
unwindBlocks(from: BlockNumber, blocksToUnwind: number): Promise<boolean> {
|
|
200
201
|
return this.#blockStore.unwindBlocks(from, blocksToUnwind);
|
|
201
202
|
}
|
|
202
203
|
|
|
203
|
-
getPublishedBlock(number:
|
|
204
|
+
getPublishedBlock(number: BlockNumber): Promise<PublishedL2Block | undefined> {
|
|
204
205
|
return this.#blockStore.getBlock(number);
|
|
205
206
|
}
|
|
206
207
|
|
|
@@ -219,7 +220,7 @@ export class KVArchiverDataStore implements ArchiverDataStore, ContractDataSourc
|
|
|
219
220
|
* @param limit - The number of blocks to return.
|
|
220
221
|
* @returns The requested L2 blocks
|
|
221
222
|
*/
|
|
222
|
-
getPublishedBlocks(start:
|
|
223
|
+
getPublishedBlocks(start: BlockNumber, limit: number): Promise<PublishedL2Block[]> {
|
|
223
224
|
return toArray(this.#blockStore.getBlocks(start, limit));
|
|
224
225
|
}
|
|
225
226
|
|
|
@@ -230,7 +231,7 @@ export class KVArchiverDataStore implements ArchiverDataStore, ContractDataSourc
|
|
|
230
231
|
* @param limit - The number of blocks to return.
|
|
231
232
|
* @returns The requested L2 blocks
|
|
232
233
|
*/
|
|
233
|
-
getBlockHeaders(start:
|
|
234
|
+
getBlockHeaders(start: BlockNumber, limit: number): Promise<BlockHeader[]> {
|
|
234
235
|
return toArray(this.#blockStore.getBlockHeaders(start, limit));
|
|
235
236
|
}
|
|
236
237
|
|
|
@@ -303,7 +304,7 @@ export class KVArchiverDataStore implements ArchiverDataStore, ContractDataSourc
|
|
|
303
304
|
* @param blockNumber - L2 block number to get messages for.
|
|
304
305
|
* @returns The L1 to L2 messages/leaves of the messages subtree (throws if not found).
|
|
305
306
|
*/
|
|
306
|
-
getL1ToL2Messages(blockNumber:
|
|
307
|
+
getL1ToL2Messages(blockNumber: BlockNumber): Promise<Fr[]> {
|
|
307
308
|
return this.#messageStore.getL1ToL2Messages(blockNumber);
|
|
308
309
|
}
|
|
309
310
|
|
|
@@ -313,7 +314,7 @@ export class KVArchiverDataStore implements ArchiverDataStore, ContractDataSourc
|
|
|
313
314
|
* @param limit - The maximum number of blocks to retrieve logs from.
|
|
314
315
|
* @returns An array of private logs from the specified range of blocks.
|
|
315
316
|
*/
|
|
316
|
-
getPrivateLogs(from:
|
|
317
|
+
getPrivateLogs(from: BlockNumber, limit: number): Promise<PrivateLog[]> {
|
|
317
318
|
return this.#logStore.getPrivateLogs(from, limit);
|
|
318
319
|
}
|
|
319
320
|
|
|
@@ -362,15 +363,15 @@ export class KVArchiverDataStore implements ArchiverDataStore, ContractDataSourc
|
|
|
362
363
|
* Gets the number of the latest L2 block processed.
|
|
363
364
|
* @returns The number of the latest L2 block processed.
|
|
364
365
|
*/
|
|
365
|
-
getSynchedL2BlockNumber(): Promise<
|
|
366
|
+
getSynchedL2BlockNumber(): Promise<BlockNumber> {
|
|
366
367
|
return this.#blockStore.getSynchedL2BlockNumber();
|
|
367
368
|
}
|
|
368
369
|
|
|
369
|
-
getProvenL2BlockNumber(): Promise<
|
|
370
|
+
getProvenL2BlockNumber(): Promise<BlockNumber> {
|
|
370
371
|
return this.#blockStore.getProvenL2BlockNumber();
|
|
371
372
|
}
|
|
372
373
|
|
|
373
|
-
async setProvenL2BlockNumber(blockNumber:
|
|
374
|
+
async setProvenL2BlockNumber(blockNumber: BlockNumber) {
|
|
374
375
|
await this.#blockStore.setProvenL2BlockNumber(blockNumber);
|
|
375
376
|
}
|
|
376
377
|
|
|
@@ -400,7 +401,7 @@ export class KVArchiverDataStore implements ArchiverDataStore, ContractDataSourc
|
|
|
400
401
|
return this.db.estimateSize();
|
|
401
402
|
}
|
|
402
403
|
|
|
403
|
-
public rollbackL1ToL2MessagesToL2Block(targetBlockNumber:
|
|
404
|
+
public rollbackL1ToL2MessagesToL2Block(targetBlockNumber: BlockNumber): Promise<void> {
|
|
404
405
|
return this.#messageStore.rollbackL1ToL2MessagesToL2Block(targetBlockNumber);
|
|
405
406
|
}
|
|
406
407
|
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { INITIAL_L2_BLOCK_NUM, MAX_NOTE_HASHES_PER_TX } from '@aztec/constants';
|
|
2
|
+
import { BlockNumber } from '@aztec/foundation/branded-types';
|
|
2
3
|
import type { Fr } from '@aztec/foundation/fields';
|
|
3
4
|
import { createLogger } from '@aztec/foundation/log';
|
|
4
5
|
import { BufferReader, numToUInt32BE } from '@aztec/foundation/serialize';
|
|
@@ -389,9 +390,9 @@ export class LogStore {
|
|
|
389
390
|
const log = txLogs[logIndex];
|
|
390
391
|
if (!filter.contractAddress || log.contractAddress.equals(filter.contractAddress)) {
|
|
391
392
|
if (log instanceof ContractClassLog) {
|
|
392
|
-
results.push(new ExtendedContractClassLog(new LogId(blockNumber, txIndex, logIndex), log));
|
|
393
|
+
results.push(new ExtendedContractClassLog(new LogId(BlockNumber(blockNumber), txIndex, logIndex), log));
|
|
393
394
|
} else {
|
|
394
|
-
results.push(new ExtendedPublicLog(new LogId(blockNumber, txIndex, logIndex), log));
|
|
395
|
+
results.push(new ExtendedPublicLog(new LogId(BlockNumber(blockNumber), txIndex, logIndex), log));
|
|
395
396
|
}
|
|
396
397
|
|
|
397
398
|
if (results.length >= this.#logsMaxPageSize) {
|
|
@@ -1,14 +1,15 @@
|
|
|
1
|
+
import { BlockNumber } from '@aztec/foundation/branded-types';
|
|
1
2
|
import { Buffer16, Buffer32 } from '@aztec/foundation/buffer';
|
|
2
3
|
import { keccak256 } from '@aztec/foundation/crypto';
|
|
3
4
|
import { Fr } from '@aztec/foundation/fields';
|
|
4
5
|
import { BufferReader, bigintToUInt64BE, numToUInt32BE, serializeToBuffer } from '@aztec/foundation/serialize';
|
|
5
|
-
import type { UInt32 } from '@aztec/stdlib/types';
|
|
6
6
|
|
|
7
7
|
export type InboxMessage = {
|
|
8
8
|
index: bigint;
|
|
9
9
|
leaf: Fr;
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
// TODO: should be checkpointNumber
|
|
11
|
+
l2BlockNumber: BlockNumber;
|
|
12
|
+
l1BlockNumber: bigint; // L1 block number - NOT Aztec L2
|
|
12
13
|
l1BlockHash: Buffer32;
|
|
13
14
|
rollingHash: Buffer16;
|
|
14
15
|
};
|
|
@@ -35,7 +36,7 @@ export function deserializeInboxMessage(buffer: Buffer): InboxMessage {
|
|
|
35
36
|
const leaf = reader.readObject(Fr);
|
|
36
37
|
const l1BlockHash = reader.readObject(Buffer32);
|
|
37
38
|
const l1BlockNumber = BigInt(reader.readNumber());
|
|
38
|
-
const l2BlockNumber = reader.readNumber();
|
|
39
|
+
const l2BlockNumber = BlockNumber(reader.readNumber());
|
|
39
40
|
const rollingHash = reader.readObject(Buffer16);
|
|
40
41
|
return { index, leaf, l1BlockHash, l1BlockNumber, l2BlockNumber, rollingHash };
|
|
41
42
|
}
|
|
@@ -1 +1,2 @@
|
|
|
1
|
-
export type { PublishedL2Block
|
|
1
|
+
export type { PublishedL2Block } from '@aztec/stdlib/block';
|
|
2
|
+
export type { L1PublishedData, PublishedCheckpoint } from '@aztec/stdlib/checkpoint';
|
|
@@ -1,60 +1,77 @@
|
|
|
1
1
|
import type { EpochCache } from '@aztec/epoch-cache';
|
|
2
|
+
import { EpochNumber } from '@aztec/foundation/branded-types';
|
|
2
3
|
import { compactArray } from '@aztec/foundation/collection';
|
|
3
4
|
import type { Logger } from '@aztec/foundation/log';
|
|
4
5
|
import {
|
|
5
|
-
type
|
|
6
|
+
type AttestationInfo,
|
|
6
7
|
type ValidateBlockNegativeResult,
|
|
7
8
|
type ValidateBlockResult,
|
|
8
|
-
|
|
9
|
+
getAttestationInfoFromPayload,
|
|
9
10
|
} from '@aztec/stdlib/block';
|
|
11
|
+
import type { PublishedCheckpoint } from '@aztec/stdlib/checkpoint';
|
|
10
12
|
import { type L1RollupConstants, getEpochAtSlot } from '@aztec/stdlib/epoch-helpers';
|
|
13
|
+
import { ConsensusPayload } from '@aztec/stdlib/p2p';
|
|
11
14
|
|
|
12
15
|
export type { ValidateBlockResult };
|
|
13
16
|
|
|
14
17
|
/**
|
|
15
|
-
*
|
|
18
|
+
* Extracts attestation information from a published checkpoint.
|
|
19
|
+
* Returns info for each attestation, preserving array indices.
|
|
20
|
+
*/
|
|
21
|
+
export function getAttestationInfoFromPublishedCheckpoint({
|
|
22
|
+
checkpoint,
|
|
23
|
+
attestations,
|
|
24
|
+
}: PublishedCheckpoint): AttestationInfo[] {
|
|
25
|
+
const payload = ConsensusPayload.fromCheckpoint(checkpoint);
|
|
26
|
+
return getAttestationInfoFromPayload(payload, attestations);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Validates the attestations submitted for the given checkpoint.
|
|
16
31
|
* Returns true if the attestations are valid and sufficient, false otherwise.
|
|
17
32
|
*/
|
|
18
|
-
export async function
|
|
19
|
-
|
|
33
|
+
export async function validateCheckpointAttestations(
|
|
34
|
+
publishedCheckpoint: PublishedCheckpoint,
|
|
20
35
|
epochCache: EpochCache,
|
|
21
36
|
constants: Pick<L1RollupConstants, 'epochDuration'>,
|
|
22
37
|
logger?: Logger,
|
|
23
38
|
): Promise<ValidateBlockResult> {
|
|
24
|
-
const attestorInfos =
|
|
39
|
+
const attestorInfos = getAttestationInfoFromPublishedCheckpoint(publishedCheckpoint);
|
|
25
40
|
const attestors = compactArray(attestorInfos.map(info => ('address' in info ? info.address : undefined)));
|
|
26
|
-
const {
|
|
27
|
-
const
|
|
28
|
-
const archiveRoot =
|
|
29
|
-
const slot =
|
|
30
|
-
const epoch = getEpochAtSlot(slot, constants);
|
|
41
|
+
const { checkpoint, attestations } = publishedCheckpoint;
|
|
42
|
+
const headerHash = checkpoint.header.hash();
|
|
43
|
+
const archiveRoot = checkpoint.archive.root.toString();
|
|
44
|
+
const slot = checkpoint.header.slotNumber;
|
|
45
|
+
const epoch: EpochNumber = getEpochAtSlot(slot, constants);
|
|
31
46
|
const { committee, seed } = await epochCache.getCommitteeForEpoch(epoch);
|
|
32
|
-
const logData = {
|
|
47
|
+
const logData = { checkpointNumber: checkpoint.number, slot, epoch, headerHash, archiveRoot };
|
|
33
48
|
|
|
34
|
-
logger?.debug(`Validating attestations for
|
|
49
|
+
logger?.debug(`Validating attestations for checkpoint ${checkpoint.number} at slot ${slot} in epoch ${epoch}`, {
|
|
35
50
|
committee: (committee ?? []).map(member => member.toString()),
|
|
36
51
|
recoveredAttestors: attestorInfos,
|
|
37
|
-
postedAttestations:
|
|
52
|
+
postedAttestations: attestations.map(a => (a.address.isZero() ? a.signature : a.address).toString()),
|
|
38
53
|
...logData,
|
|
39
54
|
});
|
|
40
55
|
|
|
41
56
|
if (!committee || committee.length === 0) {
|
|
42
|
-
logger?.warn(
|
|
57
|
+
logger?.warn(
|
|
58
|
+
`No committee found for epoch ${epoch} at slot ${slot}. Accepting checkpoint without validation.`,
|
|
59
|
+
logData,
|
|
60
|
+
);
|
|
43
61
|
return { valid: true };
|
|
44
62
|
}
|
|
45
63
|
|
|
46
|
-
const committeeSet = new Set(committee.map(member => member.toString()));
|
|
47
64
|
const requiredAttestationCount = Math.floor((committee.length * 2) / 3) + 1;
|
|
48
65
|
|
|
49
66
|
const failedValidationResult = <TReason extends ValidateBlockNegativeResult['reason']>(reason: TReason) => ({
|
|
50
67
|
valid: false as const,
|
|
51
68
|
reason,
|
|
52
|
-
block:
|
|
69
|
+
block: checkpoint.blocks[0].toBlockInfo(),
|
|
53
70
|
committee,
|
|
54
71
|
seed,
|
|
55
72
|
epoch,
|
|
56
73
|
attestors,
|
|
57
|
-
attestations
|
|
74
|
+
attestations,
|
|
58
75
|
});
|
|
59
76
|
|
|
60
77
|
for (let i = 0; i < attestorInfos.length; i++) {
|
|
@@ -70,15 +87,20 @@ export async function validateBlockAttestations(
|
|
|
70
87
|
return { ...failedValidationResult('invalid-attestation'), invalidIndex: i };
|
|
71
88
|
}
|
|
72
89
|
|
|
73
|
-
// Check if the attestor
|
|
90
|
+
// Check if the attestor at this index matches the committee member at the same index
|
|
74
91
|
if (info.status === 'recovered-from-signature' || info.status === 'provided-as-address') {
|
|
75
92
|
const signer = info.address.toString();
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
93
|
+
const expectedCommitteeMember = committee[i]?.toString();
|
|
94
|
+
|
|
95
|
+
if (!expectedCommitteeMember || signer !== expectedCommitteeMember) {
|
|
96
|
+
logger?.warn(
|
|
97
|
+
`Attestation at index ${i} from ${signer} does not match expected committee member ${expectedCommitteeMember} at slot ${slot}`,
|
|
98
|
+
{
|
|
99
|
+
committee,
|
|
100
|
+
invalidIndex: i,
|
|
101
|
+
...logData,
|
|
102
|
+
},
|
|
103
|
+
);
|
|
82
104
|
return { ...failedValidationResult('invalid-attestation'), invalidIndex: i };
|
|
83
105
|
}
|
|
84
106
|
}
|
|
@@ -86,7 +108,7 @@ export async function validateBlockAttestations(
|
|
|
86
108
|
|
|
87
109
|
const validAttestationCount = attestorInfos.filter(info => info.status === 'recovered-from-signature').length;
|
|
88
110
|
if (validAttestationCount < requiredAttestationCount) {
|
|
89
|
-
logger?.warn(`Insufficient attestations for
|
|
111
|
+
logger?.warn(`Insufficient attestations for checkpoint at slot ${slot}`, {
|
|
90
112
|
requiredAttestations: requiredAttestationCount,
|
|
91
113
|
actualAttestations: validAttestationCount,
|
|
92
114
|
...logData,
|
|
@@ -94,6 +116,9 @@ export async function validateBlockAttestations(
|
|
|
94
116
|
return failedValidationResult('insufficient-attestations');
|
|
95
117
|
}
|
|
96
118
|
|
|
97
|
-
logger?.debug(
|
|
119
|
+
logger?.debug(
|
|
120
|
+
`Checkpoint attestations validated successfully for checkpoint ${checkpoint.number} at slot ${slot}`,
|
|
121
|
+
logData,
|
|
122
|
+
);
|
|
98
123
|
return { valid: true };
|
|
99
124
|
}
|
package/src/factory.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { BlockNumber } from '@aztec/foundation/branded-types';
|
|
1
2
|
import { createLogger } from '@aztec/foundation/log';
|
|
2
3
|
import type { DataStoreConfig } from '@aztec/kv-store/config';
|
|
3
4
|
import { createStore } from '@aztec/kv-store/lmdb-v2';
|
|
@@ -59,7 +60,7 @@ async function registerProtocolContracts(store: KVArchiverDataStore) {
|
|
|
59
60
|
|
|
60
61
|
await store.registerContractFunctionSignatures(publicFunctionSignatures);
|
|
61
62
|
const bytecodeCommitment = await computePublicBytecodeCommitment(contractClassPublic.packedBytecode);
|
|
62
|
-
await store.addContractClasses([contractClassPublic], [bytecodeCommitment], blockNumber);
|
|
63
|
-
await store.addContractInstances([contract.instance], blockNumber);
|
|
63
|
+
await store.addContractClasses([contractClassPublic], [bytecodeCommitment], BlockNumber(blockNumber));
|
|
64
|
+
await store.addContractInstances([contract.instance], BlockNumber(blockNumber));
|
|
64
65
|
}
|
|
65
66
|
}
|
package/src/index.ts
CHANGED
|
@@ -2,4 +2,4 @@ export * from './archiver/index.js';
|
|
|
2
2
|
export * from './factory.js';
|
|
3
3
|
export * from './rpc/index.js';
|
|
4
4
|
|
|
5
|
-
export {
|
|
5
|
+
export { retrieveL2ProofVerifiedEvents } from './archiver/data_retrieval.js';
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
+
import type { CheckpointNumber } from '@aztec/foundation/branded-types';
|
|
1
2
|
import type { Fr } from '@aztec/foundation/fields';
|
|
2
|
-
import
|
|
3
|
+
import { L2Block, type L2BlockSource } from '@aztec/stdlib/block';
|
|
4
|
+
import type { Checkpoint } from '@aztec/stdlib/checkpoint';
|
|
3
5
|
import type { L1ToL2MessageSource } from '@aztec/stdlib/messaging';
|
|
4
6
|
|
|
5
7
|
import { MockL1ToL2MessageSource } from './mock_l1_to_l2_message_source.js';
|
|
@@ -22,36 +24,45 @@ export class MockArchiver extends MockL2BlockSource implements L2BlockSource, L1
|
|
|
22
24
|
getL1ToL2MessageIndex(_l1ToL2Message: Fr): Promise<bigint | undefined> {
|
|
23
25
|
return this.messageSource.getL1ToL2MessageIndex(_l1ToL2Message);
|
|
24
26
|
}
|
|
27
|
+
|
|
28
|
+
getL1ToL2MessagesForCheckpoint(checkpointNumber: CheckpointNumber): Promise<Fr[]> {
|
|
29
|
+
// TODO: Implement this properly. This only works when we have one block per checkpoint.
|
|
30
|
+
return this.messageSource.getL1ToL2Messages(checkpointNumber);
|
|
31
|
+
}
|
|
25
32
|
}
|
|
26
33
|
|
|
27
34
|
/**
|
|
28
35
|
* A mocked implementation of the archiver with a set of precomputed blocks and messages.
|
|
29
36
|
*/
|
|
30
37
|
export class MockPrefilledArchiver extends MockArchiver {
|
|
31
|
-
private
|
|
38
|
+
private prefilled: Checkpoint[] = [];
|
|
32
39
|
|
|
33
|
-
constructor(
|
|
40
|
+
constructor(prefilled: { checkpoint: Checkpoint; messages: Fr[] }[]) {
|
|
34
41
|
super();
|
|
35
|
-
this.
|
|
36
|
-
messages.forEach((msgs, i) => this.setL1ToL2Messages(i + 1, msgs));
|
|
42
|
+
this.setPrefilled(prefilled);
|
|
37
43
|
}
|
|
38
44
|
|
|
39
|
-
public
|
|
40
|
-
for (const
|
|
41
|
-
this.
|
|
45
|
+
public setPrefilled(prefilled: { checkpoint: Checkpoint; messages: Fr[] }[]) {
|
|
46
|
+
for (const { checkpoint, messages } of prefilled) {
|
|
47
|
+
this.prefilled[checkpoint.number - 1] = checkpoint;
|
|
48
|
+
if (checkpoint.blocks.length !== 1) {
|
|
49
|
+
throw new Error('Prefilled checkpoint must only have 1 block at the moment.');
|
|
50
|
+
}
|
|
51
|
+
this.setL1ToL2Messages(checkpoint.blocks[0].number, messages);
|
|
42
52
|
}
|
|
43
|
-
messages.forEach((msgs, i) => this.setL1ToL2Messages(blocks[i].number, msgs));
|
|
44
53
|
}
|
|
45
54
|
|
|
46
55
|
public override createBlocks(numBlocks: number) {
|
|
47
|
-
|
|
56
|
+
const flattenedBlocks = this.prefilled.flatMap(c => c.blocks);
|
|
57
|
+
if (this.l2Blocks.length + numBlocks > flattenedBlocks.length) {
|
|
48
58
|
throw new Error(
|
|
49
59
|
`Not enough precomputed blocks to create ${numBlocks} more blocks (already at ${this.l2Blocks.length})`,
|
|
50
60
|
);
|
|
51
61
|
}
|
|
52
62
|
|
|
53
63
|
const fromBlock = this.l2Blocks.length;
|
|
54
|
-
|
|
64
|
+
// TODO: Add L2 blocks and checkpoints separately once archiver has the apis for that.
|
|
65
|
+
this.addBlocks(this.prefilled.slice(fromBlock, fromBlock + numBlocks).map(c => L2Block.fromCheckpoint(c)));
|
|
55
66
|
return Promise.resolve();
|
|
56
67
|
}
|
|
57
68
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { BlockNumber, type CheckpointNumber } from '@aztec/foundation/branded-types';
|
|
1
2
|
import { Fr } from '@aztec/foundation/fields';
|
|
2
3
|
import type { L2Tips } from '@aztec/stdlib/block';
|
|
3
4
|
import type { L1ToL2MessageSource } from '@aztec/stdlib/messaging';
|
|
@@ -18,6 +19,11 @@ export class MockL1ToL2MessageSource implements L1ToL2MessageSource {
|
|
|
18
19
|
this.blockNumber = blockNumber;
|
|
19
20
|
}
|
|
20
21
|
|
|
22
|
+
getL1ToL2MessagesForCheckpoint(checkpointNumber: CheckpointNumber): Promise<Fr[]> {
|
|
23
|
+
// TODO: Implement this properly. This only works when we have one block per checkpoint.
|
|
24
|
+
return this.getL1ToL2Messages(checkpointNumber);
|
|
25
|
+
}
|
|
26
|
+
|
|
21
27
|
getL1ToL2Messages(blockNumber: number): Promise<Fr[]> {
|
|
22
28
|
return Promise.resolve(this.messagesPerBlock.get(blockNumber) ?? []);
|
|
23
29
|
}
|
|
@@ -26,13 +32,13 @@ export class MockL1ToL2MessageSource implements L1ToL2MessageSource {
|
|
|
26
32
|
throw new Error('Method not implemented.');
|
|
27
33
|
}
|
|
28
34
|
|
|
29
|
-
getBlockNumber()
|
|
30
|
-
return Promise.resolve(this.blockNumber);
|
|
35
|
+
getBlockNumber() {
|
|
36
|
+
return Promise.resolve(BlockNumber(this.blockNumber));
|
|
31
37
|
}
|
|
32
38
|
|
|
33
39
|
getL2Tips(): Promise<L2Tips> {
|
|
34
40
|
const number = this.blockNumber;
|
|
35
|
-
const tip = { number, hash: new Fr(number).toString() };
|
|
41
|
+
const tip = { number: BlockNumber(number), hash: new Fr(number).toString() };
|
|
36
42
|
return Promise.resolve({
|
|
37
43
|
latest: tip,
|
|
38
44
|
proven: tip,
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { GENESIS_ARCHIVE_ROOT } from '@aztec/constants';
|
|
2
2
|
import { DefaultL1ContractsConfig } from '@aztec/ethereum';
|
|
3
|
+
import { BlockNumber, CheckpointNumber, EpochNumber, SlotNumber } from '@aztec/foundation/branded-types';
|
|
3
4
|
import { Buffer32 } from '@aztec/foundation/buffer';
|
|
4
5
|
import { EthAddress } from '@aztec/foundation/eth-address';
|
|
5
6
|
import { Fr } from '@aztec/foundation/fields';
|
|
@@ -14,6 +15,7 @@ import {
|
|
|
14
15
|
PublishedL2Block,
|
|
15
16
|
type ValidateBlockResult,
|
|
16
17
|
} from '@aztec/stdlib/block';
|
|
18
|
+
import type { Checkpoint } from '@aztec/stdlib/checkpoint';
|
|
17
19
|
import type { ContractClassPublic, ContractDataSource, ContractInstanceWithAddress } from '@aztec/stdlib/contract';
|
|
18
20
|
import { EmptyL1RollupConstants, type L1RollupConstants, getSlotRangeForEpoch } from '@aztec/stdlib/epoch-helpers';
|
|
19
21
|
import { type BlockHeader, TxHash, TxReceipt, TxStatus } from '@aztec/stdlib/tx';
|
|
@@ -33,7 +35,7 @@ export class MockL2BlockSource implements L2BlockSource, ContractDataSource {
|
|
|
33
35
|
public async createBlocks(numBlocks: number) {
|
|
34
36
|
for (let i = 0; i < numBlocks; i++) {
|
|
35
37
|
const blockNum = this.l2Blocks.length + 1;
|
|
36
|
-
const block = await L2Block.random(blockNum);
|
|
38
|
+
const block = await L2Block.random(BlockNumber(blockNum));
|
|
37
39
|
this.l2Blocks.push(block);
|
|
38
40
|
}
|
|
39
41
|
|
|
@@ -82,11 +84,11 @@ export class MockL2BlockSource implements L2BlockSource, ContractDataSource {
|
|
|
82
84
|
* @returns In this mock instance, returns the number of L2 blocks that we've mocked.
|
|
83
85
|
*/
|
|
84
86
|
public getBlockNumber() {
|
|
85
|
-
return Promise.resolve(this.l2Blocks.length);
|
|
87
|
+
return Promise.resolve(BlockNumber(this.l2Blocks.length));
|
|
86
88
|
}
|
|
87
89
|
|
|
88
|
-
public getProvenBlockNumber()
|
|
89
|
-
return Promise.resolve(this.provenBlockNumber);
|
|
90
|
+
public getProvenBlockNumber() {
|
|
91
|
+
return Promise.resolve(BlockNumber(this.provenBlockNumber));
|
|
90
92
|
}
|
|
91
93
|
|
|
92
94
|
/**
|
|
@@ -112,6 +114,16 @@ export class MockL2BlockSource implements L2BlockSource, ContractDataSource {
|
|
|
112
114
|
);
|
|
113
115
|
}
|
|
114
116
|
|
|
117
|
+
public async getPublishedCheckpoints(from: CheckpointNumber, limit: number) {
|
|
118
|
+
// TODO: Implement this properly. This only works when we have one block per checkpoint.
|
|
119
|
+
return (await this.getPublishedBlocks(from, limit)).map(block => block.toPublishedCheckpoint());
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
public async getCheckpointByArchive(archive: Fr): Promise<Checkpoint | undefined> {
|
|
123
|
+
// TODO: Implement this properly. This only works when we have one block per checkpoint.
|
|
124
|
+
return (await this.getPublishedBlockByArchive(archive))?.block.toCheckpoint();
|
|
125
|
+
}
|
|
126
|
+
|
|
115
127
|
public async getPublishedBlocks(from: number, limit: number, proven?: boolean) {
|
|
116
128
|
const blocks = await this.getBlocks(from, limit, proven);
|
|
117
129
|
return blocks.map(block =>
|
|
@@ -182,17 +194,22 @@ export class MockL2BlockSource implements L2BlockSource, ContractDataSource {
|
|
|
182
194
|
return Promise.resolve(this.l2Blocks.at(typeof number === 'number' ? number - 1 : -1)?.getBlockHeader());
|
|
183
195
|
}
|
|
184
196
|
|
|
185
|
-
|
|
197
|
+
getCheckpointsForEpoch(epochNumber: EpochNumber): Promise<Checkpoint[]> {
|
|
198
|
+
// TODO: Implement this properly. This only works when we have one block per checkpoint.
|
|
199
|
+
return this.getBlocksForEpoch(epochNumber).then(blocks => blocks.map(b => b.toCheckpoint()));
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
getBlocksForEpoch(epochNumber: EpochNumber): Promise<L2Block[]> {
|
|
186
203
|
const epochDuration = DefaultL1ContractsConfig.aztecEpochDuration;
|
|
187
204
|
const [start, end] = getSlotRangeForEpoch(epochNumber, { epochDuration });
|
|
188
205
|
const blocks = this.l2Blocks.filter(b => {
|
|
189
|
-
const slot = b.header.globalVariables.slotNumber
|
|
206
|
+
const slot = b.header.globalVariables.slotNumber;
|
|
190
207
|
return slot >= start && slot <= end;
|
|
191
208
|
});
|
|
192
209
|
return Promise.resolve(blocks);
|
|
193
210
|
}
|
|
194
211
|
|
|
195
|
-
async getBlockHeadersForEpoch(epochNumber:
|
|
212
|
+
async getBlockHeadersForEpoch(epochNumber: EpochNumber): Promise<BlockHeader[]> {
|
|
196
213
|
const blocks = await this.getBlocksForEpoch(epochNumber);
|
|
197
214
|
return blocks.map(b => b.getBlockHeader());
|
|
198
215
|
}
|
|
@@ -254,29 +271,29 @@ export class MockL2BlockSource implements L2BlockSource, ContractDataSource {
|
|
|
254
271
|
|
|
255
272
|
return {
|
|
256
273
|
latest: {
|
|
257
|
-
number: latest,
|
|
274
|
+
number: BlockNumber(latest),
|
|
258
275
|
hash: (await latestBlock?.hash())?.toString(),
|
|
259
276
|
},
|
|
260
277
|
proven: {
|
|
261
|
-
number: proven,
|
|
278
|
+
number: BlockNumber(proven),
|
|
262
279
|
hash: (await provenBlock?.hash())?.toString(),
|
|
263
280
|
},
|
|
264
281
|
finalized: {
|
|
265
|
-
number: finalized,
|
|
282
|
+
number: BlockNumber(finalized),
|
|
266
283
|
hash: (await finalizedBlock?.hash())?.toString(),
|
|
267
284
|
},
|
|
268
285
|
};
|
|
269
286
|
}
|
|
270
287
|
|
|
271
|
-
getL2EpochNumber(): Promise<
|
|
288
|
+
getL2EpochNumber(): Promise<EpochNumber> {
|
|
272
289
|
throw new Error('Method not implemented.');
|
|
273
290
|
}
|
|
274
291
|
|
|
275
|
-
getL2SlotNumber(): Promise<
|
|
292
|
+
getL2SlotNumber(): Promise<SlotNumber> {
|
|
276
293
|
throw new Error('Method not implemented.');
|
|
277
294
|
}
|
|
278
295
|
|
|
279
|
-
isEpochComplete(_epochNumber:
|
|
296
|
+
isEpochComplete(_epochNumber: EpochNumber): Promise<boolean> {
|
|
280
297
|
throw new Error('Method not implemented.');
|
|
281
298
|
}
|
|
282
299
|
|
package/src/test/mock_structs.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { BlockNumber } from '@aztec/foundation/branded-types';
|
|
1
2
|
import { Buffer16, Buffer32 } from '@aztec/foundation/buffer';
|
|
2
3
|
import { randomBigInt, randomInt } from '@aztec/foundation/crypto';
|
|
3
4
|
import { Fr } from '@aztec/foundation/fields';
|
|
@@ -19,7 +20,7 @@ export function makeInboxMessage(
|
|
|
19
20
|
return {
|
|
20
21
|
index,
|
|
21
22
|
leaf,
|
|
22
|
-
l2BlockNumber,
|
|
23
|
+
l2BlockNumber: BlockNumber(l2BlockNumber),
|
|
23
24
|
l1BlockNumber,
|
|
24
25
|
l1BlockHash,
|
|
25
26
|
rollingHash,
|
|
@@ -39,7 +40,7 @@ export function makeInboxMessages(
|
|
|
39
40
|
let rollingHash = initialHash;
|
|
40
41
|
for (let i = 0; i < count; i++) {
|
|
41
42
|
const leaf = Fr.random();
|
|
42
|
-
const l2BlockNumber = i + initialL2BlockNumber;
|
|
43
|
+
const l2BlockNumber = BlockNumber(i + initialL2BlockNumber);
|
|
43
44
|
const message = overrideFn(makeInboxMessage(rollingHash, { leaf, l2BlockNumber }), i);
|
|
44
45
|
rollingHash = message.rollingHash;
|
|
45
46
|
messages.push(message);
|