@aztec/archiver 0.0.1-commit.993d52e → 0.0.1-commit.9badcec54
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 +12 -6
- package/dest/archiver.d.ts +8 -7
- package/dest/archiver.d.ts.map +1 -1
- package/dest/archiver.js +64 -22
- package/dest/config.d.ts +3 -3
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +3 -2
- package/dest/errors.d.ts +34 -10
- package/dest/errors.d.ts.map +1 -1
- package/dest/errors.js +45 -16
- package/dest/factory.d.ts +4 -5
- package/dest/factory.d.ts.map +1 -1
- package/dest/factory.js +24 -21
- package/dest/l1/calldata_retriever.d.ts +1 -1
- package/dest/l1/calldata_retriever.d.ts.map +1 -1
- package/dest/l1/calldata_retriever.js +2 -1
- package/dest/l1/data_retrieval.d.ts +8 -5
- package/dest/l1/data_retrieval.d.ts.map +1 -1
- package/dest/l1/data_retrieval.js +26 -21
- package/dest/modules/data_source_base.d.ts +8 -6
- package/dest/modules/data_source_base.d.ts.map +1 -1
- package/dest/modules/data_source_base.js +11 -5
- package/dest/modules/data_store_updater.d.ts +18 -12
- package/dest/modules/data_store_updater.d.ts.map +1 -1
- package/dest/modules/data_store_updater.js +87 -77
- package/dest/modules/instrumentation.d.ts +15 -2
- package/dest/modules/instrumentation.d.ts.map +1 -1
- package/dest/modules/instrumentation.js +27 -6
- package/dest/modules/l1_synchronizer.d.ts +4 -2
- package/dest/modules/l1_synchronizer.d.ts.map +1 -1
- package/dest/modules/l1_synchronizer.js +173 -129
- package/dest/modules/validation.d.ts +1 -1
- package/dest/modules/validation.d.ts.map +1 -1
- package/dest/modules/validation.js +2 -2
- package/dest/store/block_store.d.ts +50 -16
- package/dest/store/block_store.d.ts.map +1 -1
- package/dest/store/block_store.js +290 -121
- package/dest/store/contract_class_store.d.ts +2 -3
- package/dest/store/contract_class_store.d.ts.map +1 -1
- package/dest/store/contract_class_store.js +7 -67
- package/dest/store/contract_instance_store.d.ts +1 -1
- package/dest/store/contract_instance_store.d.ts.map +1 -1
- package/dest/store/contract_instance_store.js +6 -2
- package/dest/store/kv_archiver_store.d.ts +45 -22
- package/dest/store/kv_archiver_store.d.ts.map +1 -1
- package/dest/store/kv_archiver_store.js +57 -27
- package/dest/store/l2_tips_cache.d.ts +2 -1
- package/dest/store/l2_tips_cache.d.ts.map +1 -1
- package/dest/store/l2_tips_cache.js +27 -7
- package/dest/store/log_store.d.ts +6 -3
- package/dest/store/log_store.d.ts.map +1 -1
- package/dest/store/log_store.js +95 -20
- package/dest/store/message_store.d.ts +5 -1
- package/dest/store/message_store.d.ts.map +1 -1
- package/dest/store/message_store.js +21 -9
- package/dest/test/fake_l1_state.d.ts +16 -1
- package/dest/test/fake_l1_state.d.ts.map +1 -1
- package/dest/test/fake_l1_state.js +77 -8
- package/dest/test/mock_l1_to_l2_message_source.d.ts +1 -1
- package/dest/test/mock_l1_to_l2_message_source.d.ts.map +1 -1
- package/dest/test/mock_l1_to_l2_message_source.js +2 -1
- package/dest/test/mock_l2_block_source.d.ts +10 -4
- package/dest/test/mock_l2_block_source.d.ts.map +1 -1
- package/dest/test/mock_l2_block_source.js +35 -7
- package/dest/test/mock_structs.d.ts +4 -1
- package/dest/test/mock_structs.d.ts.map +1 -1
- package/dest/test/mock_structs.js +13 -1
- package/dest/test/noop_l1_archiver.d.ts +4 -1
- package/dest/test/noop_l1_archiver.d.ts.map +1 -1
- package/dest/test/noop_l1_archiver.js +5 -2
- package/package.json +13 -13
- package/src/archiver.ts +78 -28
- package/src/config.ts +9 -2
- package/src/errors.ts +70 -26
- package/src/factory.ts +23 -15
- package/src/l1/calldata_retriever.ts +2 -1
- package/src/l1/data_retrieval.ts +25 -21
- package/src/modules/data_source_base.ts +26 -7
- package/src/modules/data_store_updater.ts +96 -107
- package/src/modules/instrumentation.ts +39 -7
- package/src/modules/l1_synchronizer.ts +197 -161
- package/src/modules/validation.ts +2 -2
- package/src/store/block_store.ts +371 -141
- package/src/store/contract_class_store.ts +8 -106
- package/src/store/contract_instance_store.ts +8 -5
- package/src/store/kv_archiver_store.ts +81 -39
- package/src/store/l2_tips_cache.ts +58 -13
- package/src/store/log_store.ts +128 -32
- package/src/store/message_store.ts +27 -10
- package/src/structs/inbox_message.ts +1 -1
- package/src/test/fake_l1_state.ts +103 -13
- package/src/test/mock_l1_to_l2_message_source.ts +1 -0
- package/src/test/mock_l2_block_source.ts +52 -5
- package/src/test/mock_structs.ts +20 -6
- package/src/test/noop_l1_archiver.ts +7 -2
|
@@ -6,7 +6,13 @@ import { isDefined } from '@aztec/foundation/types';
|
|
|
6
6
|
import type { FunctionSelector } from '@aztec/stdlib/abi';
|
|
7
7
|
import type { AztecAddress } from '@aztec/stdlib/aztec-address';
|
|
8
8
|
import { type BlockData, type BlockHash, CheckpointedL2Block, L2Block, type L2Tips } from '@aztec/stdlib/block';
|
|
9
|
-
import {
|
|
9
|
+
import {
|
|
10
|
+
Checkpoint,
|
|
11
|
+
type CheckpointData,
|
|
12
|
+
type CommonCheckpointData,
|
|
13
|
+
type ProposedCheckpointData,
|
|
14
|
+
PublishedCheckpoint,
|
|
15
|
+
} from '@aztec/stdlib/checkpoint';
|
|
10
16
|
import type { ContractClassPublic, ContractDataSource, ContractInstanceWithAddress } from '@aztec/stdlib/contract';
|
|
11
17
|
import { type L1RollupConstants, getSlotRangeForEpoch } from '@aztec/stdlib/epoch-helpers';
|
|
12
18
|
import type { GetContractClassLogsResponse, GetPublicLogsResponse } from '@aztec/stdlib/interfaces/client';
|
|
@@ -46,9 +52,9 @@ export abstract class ArchiverDataSourceBase
|
|
|
46
52
|
|
|
47
53
|
abstract getL2Tips(): Promise<L2Tips>;
|
|
48
54
|
|
|
49
|
-
abstract
|
|
55
|
+
abstract getSyncedL2SlotNumber(): Promise<SlotNumber | undefined>;
|
|
50
56
|
|
|
51
|
-
abstract
|
|
57
|
+
abstract getSyncedL2EpochNumber(): Promise<EpochNumber | undefined>;
|
|
52
58
|
|
|
53
59
|
abstract isEpochComplete(epochNumber: EpochNumber): Promise<boolean>;
|
|
54
60
|
|
|
@@ -154,7 +160,15 @@ export abstract class ArchiverDataSourceBase
|
|
|
154
160
|
}
|
|
155
161
|
|
|
156
162
|
public getSettledTxReceipt(txHash: TxHash): Promise<TxReceipt | undefined> {
|
|
157
|
-
return this.store.getSettledTxReceipt(txHash);
|
|
163
|
+
return this.store.getSettledTxReceipt(txHash, this.l1Constants);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
public getProposedCheckpoint(): Promise<CommonCheckpointData | undefined> {
|
|
167
|
+
return this.store.getProposedCheckpoint();
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
public getProposedCheckpointOnly(): Promise<ProposedCheckpointData | undefined> {
|
|
171
|
+
return this.store.getProposedCheckpointOnly();
|
|
158
172
|
}
|
|
159
173
|
|
|
160
174
|
public isPendingChainInvalid(): Promise<boolean> {
|
|
@@ -165,16 +179,21 @@ export abstract class ArchiverDataSourceBase
|
|
|
165
179
|
return (await this.store.getPendingChainValidationStatus()) ?? { valid: true };
|
|
166
180
|
}
|
|
167
181
|
|
|
168
|
-
public getPrivateLogsByTags(
|
|
169
|
-
|
|
182
|
+
public getPrivateLogsByTags(
|
|
183
|
+
tags: SiloedTag[],
|
|
184
|
+
page?: number,
|
|
185
|
+
upToBlockNumber?: BlockNumber,
|
|
186
|
+
): Promise<TxScopedL2Log[][]> {
|
|
187
|
+
return this.store.getPrivateLogsByTags(tags, page, upToBlockNumber);
|
|
170
188
|
}
|
|
171
189
|
|
|
172
190
|
public getPublicLogsByTagsFromContract(
|
|
173
191
|
contractAddress: AztecAddress,
|
|
174
192
|
tags: Tag[],
|
|
175
193
|
page?: number,
|
|
194
|
+
upToBlockNumber?: BlockNumber,
|
|
176
195
|
): Promise<TxScopedL2Log[][]> {
|
|
177
|
-
return this.store.getPublicLogsByTagsFromContract(contractAddress, tags, page);
|
|
196
|
+
return this.store.getPublicLogsByTagsFromContract(contractAddress, tags, page, upToBlockNumber);
|
|
178
197
|
}
|
|
179
198
|
|
|
180
199
|
public getPublicLogs(filter: LogFilter): Promise<GetPublicLogsResponse> {
|
|
@@ -1,29 +1,21 @@
|
|
|
1
1
|
import { BlockNumber, CheckpointNumber } from '@aztec/foundation/branded-types';
|
|
2
|
-
import {
|
|
2
|
+
import { filterAsync } from '@aztec/foundation/collection';
|
|
3
3
|
import { createLogger } from '@aztec/foundation/log';
|
|
4
|
-
import {
|
|
5
|
-
ContractClassPublishedEvent,
|
|
6
|
-
PrivateFunctionBroadcastedEvent,
|
|
7
|
-
UtilityFunctionBroadcastedEvent,
|
|
8
|
-
} from '@aztec/protocol-contracts/class-registry';
|
|
4
|
+
import { ContractClassPublishedEvent } from '@aztec/protocol-contracts/class-registry';
|
|
9
5
|
import {
|
|
10
6
|
ContractInstancePublishedEvent,
|
|
11
7
|
ContractInstanceUpdatedEvent,
|
|
12
8
|
} from '@aztec/protocol-contracts/instance-registry';
|
|
13
9
|
import type { L2Block, ValidateCheckpointResult } from '@aztec/stdlib/block';
|
|
14
|
-
import type
|
|
10
|
+
import { type ProposedCheckpointInput, type PublishedCheckpoint, validateCheckpoint } from '@aztec/stdlib/checkpoint';
|
|
15
11
|
import {
|
|
16
|
-
type
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
isValidPrivateFunctionMembershipProof,
|
|
20
|
-
isValidUtilityFunctionMembershipProof,
|
|
12
|
+
type ContractClassPublicWithCommitment,
|
|
13
|
+
computeContractAddressFromInstance,
|
|
14
|
+
computeContractClassId,
|
|
21
15
|
} from '@aztec/stdlib/contract';
|
|
22
16
|
import type { ContractClassLog, PrivateLog, PublicLog } from '@aztec/stdlib/logs';
|
|
23
17
|
import type { UInt64 } from '@aztec/stdlib/types';
|
|
24
18
|
|
|
25
|
-
import groupBy from 'lodash.groupby';
|
|
26
|
-
|
|
27
19
|
import type { KVArchiverDataStore } from '../store/kv_archiver_store.js';
|
|
28
20
|
import type { L2TipsCache } from '../store/l2_tips_cache.js';
|
|
29
21
|
|
|
@@ -48,32 +40,32 @@ export class ArchiverDataStoreUpdater {
|
|
|
48
40
|
constructor(
|
|
49
41
|
private store: KVArchiverDataStore,
|
|
50
42
|
private l2TipsCache?: L2TipsCache,
|
|
43
|
+
private opts: { rollupManaLimit?: number } = {},
|
|
51
44
|
) {}
|
|
52
45
|
|
|
53
46
|
/**
|
|
54
|
-
* Adds proposed
|
|
55
|
-
*
|
|
56
|
-
* Extracts ContractClassPublished, ContractInstancePublished, ContractInstanceUpdated events
|
|
57
|
-
* and individually broadcasted functions from the block logs.
|
|
47
|
+
* Adds a proposed block to the store with contract class/instance extraction from logs.
|
|
48
|
+
* This is an uncheckpointed block that has been proposed by the sequencer but not yet included in a checkpoint on L1.
|
|
49
|
+
* Extracts ContractClassPublished, ContractInstancePublished, ContractInstanceUpdated events from the block logs.
|
|
58
50
|
*
|
|
59
|
-
* @param
|
|
51
|
+
* @param block - The proposed L2 block to add.
|
|
60
52
|
* @param pendingChainValidationStatus - Optional validation status to set.
|
|
61
53
|
* @returns True if the operation is successful.
|
|
62
54
|
*/
|
|
63
|
-
public async
|
|
64
|
-
|
|
55
|
+
public async addProposedBlock(
|
|
56
|
+
block: L2Block,
|
|
65
57
|
pendingChainValidationStatus?: ValidateCheckpointResult,
|
|
66
58
|
): Promise<boolean> {
|
|
67
59
|
const result = await this.store.transactionAsync(async () => {
|
|
68
|
-
await this.store.
|
|
60
|
+
await this.store.addProposedBlock(block);
|
|
69
61
|
|
|
70
62
|
const opResults = await Promise.all([
|
|
71
63
|
// Update the pending chain validation status if provided
|
|
72
64
|
pendingChainValidationStatus && this.store.setPendingChainValidationStatus(pendingChainValidationStatus),
|
|
73
|
-
// Add any logs emitted during the retrieved
|
|
74
|
-
this.store.addLogs(
|
|
75
|
-
// Unroll all logs emitted during the retrieved
|
|
76
|
-
|
|
65
|
+
// Add any logs emitted during the retrieved block
|
|
66
|
+
this.store.addLogs([block]),
|
|
67
|
+
// Unroll all logs emitted during the retrieved block and extract any contract classes and instances from it
|
|
68
|
+
this.addContractDataToDb(block),
|
|
77
69
|
]);
|
|
78
70
|
|
|
79
71
|
await this.l2TipsCache?.refresh();
|
|
@@ -86,8 +78,7 @@ export class ArchiverDataStoreUpdater {
|
|
|
86
78
|
* Reconciles local blocks with incoming checkpoints from L1.
|
|
87
79
|
* Adds new checkpoints to the store with contract class/instance extraction from logs.
|
|
88
80
|
* Prunes any local blocks that conflict with checkpoint data (by comparing archive roots).
|
|
89
|
-
* Extracts ContractClassPublished, ContractInstancePublished, ContractInstanceUpdated events
|
|
90
|
-
* and individually broadcasted functions from the checkpoint block logs.
|
|
81
|
+
* Extracts ContractClassPublished, ContractInstancePublished, ContractInstanceUpdated events from the checkpoint block logs.
|
|
91
82
|
*
|
|
92
83
|
* @param checkpoints - The published checkpoints to add.
|
|
93
84
|
* @param pendingChainValidationStatus - Optional validation status to set.
|
|
@@ -97,13 +88,17 @@ export class ArchiverDataStoreUpdater {
|
|
|
97
88
|
checkpoints: PublishedCheckpoint[],
|
|
98
89
|
pendingChainValidationStatus?: ValidateCheckpointResult,
|
|
99
90
|
): Promise<ReconcileCheckpointsResult> {
|
|
91
|
+
for (const checkpoint of checkpoints) {
|
|
92
|
+
validateCheckpoint(checkpoint.checkpoint, { rollupManaLimit: this.opts?.rollupManaLimit });
|
|
93
|
+
}
|
|
94
|
+
|
|
100
95
|
const result = await this.store.transactionAsync(async () => {
|
|
101
96
|
// Before adding checkpoints, check for conflicts with local blocks if any
|
|
102
97
|
const { prunedBlocks, lastAlreadyInsertedBlockNumber } = await this.pruneMismatchingLocalBlocks(checkpoints);
|
|
103
98
|
|
|
104
99
|
await this.store.addCheckpoints(checkpoints);
|
|
105
100
|
|
|
106
|
-
// Filter out blocks that were already inserted via
|
|
101
|
+
// Filter out blocks that were already inserted via addProposedBlock() to avoid duplicating logs/contract data
|
|
107
102
|
const newBlocks = checkpoints
|
|
108
103
|
.flatMap((ch: PublishedCheckpoint) => ch.checkpoint.blocks)
|
|
109
104
|
.filter(b => lastAlreadyInsertedBlockNumber === undefined || b.number > lastAlreadyInsertedBlockNumber);
|
|
@@ -123,6 +118,15 @@ export class ArchiverDataStoreUpdater {
|
|
|
123
118
|
return result;
|
|
124
119
|
}
|
|
125
120
|
|
|
121
|
+
public async setProposedCheckpoint(proposedCheckpoint: ProposedCheckpointInput) {
|
|
122
|
+
const result = await this.store.transactionAsync(async () => {
|
|
123
|
+
await this.store.setProposedCheckpoint(proposedCheckpoint);
|
|
124
|
+
await this.l2TipsCache?.refresh();
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
return result;
|
|
128
|
+
}
|
|
129
|
+
|
|
126
130
|
/**
|
|
127
131
|
* Checks for local proposed blocks that do not match the ones to be checkpointed and prunes them.
|
|
128
132
|
* This method handles multiple checkpoints but returns after pruning the first conflict found.
|
|
@@ -173,7 +177,7 @@ export class ArchiverDataStoreUpdater {
|
|
|
173
177
|
this.log.verbose(`Block number ${blockNumber} already inserted and matches checkpoint`, blockInfos);
|
|
174
178
|
lastAlreadyInsertedBlockNumber = blockNumber;
|
|
175
179
|
} else {
|
|
176
|
-
this.log.
|
|
180
|
+
this.log.info(`Conflict detected at block ${blockNumber} between checkpointed and local block`, blockInfos);
|
|
177
181
|
const prunedBlocks = await this.removeBlocksAfter(BlockNumber(blockNumber - 1));
|
|
178
182
|
return { prunedBlocks, lastAlreadyInsertedBlockNumber };
|
|
179
183
|
}
|
|
@@ -216,6 +220,10 @@ export class ArchiverDataStoreUpdater {
|
|
|
216
220
|
}
|
|
217
221
|
|
|
218
222
|
const result = await this.removeBlocksAfter(blockNumber);
|
|
223
|
+
|
|
224
|
+
// Clear the proposed checkpoint if it exists, since its blocks have been pruned
|
|
225
|
+
await this.store.deleteProposedCheckpoint();
|
|
226
|
+
|
|
219
227
|
await this.l2TipsCache?.refresh();
|
|
220
228
|
return result;
|
|
221
229
|
});
|
|
@@ -276,6 +284,17 @@ export class ArchiverDataStoreUpdater {
|
|
|
276
284
|
});
|
|
277
285
|
}
|
|
278
286
|
|
|
287
|
+
/**
|
|
288
|
+
* Updates the finalized checkpoint number and refreshes the L2 tips cache.
|
|
289
|
+
* @param checkpointNumber - The checkpoint number to set as finalized.
|
|
290
|
+
*/
|
|
291
|
+
public async setFinalizedCheckpointNumber(checkpointNumber: CheckpointNumber): Promise<void> {
|
|
292
|
+
await this.store.transactionAsync(async () => {
|
|
293
|
+
await this.store.setFinalizedCheckpointNumber(checkpointNumber);
|
|
294
|
+
await this.l2TipsCache?.refresh();
|
|
295
|
+
});
|
|
296
|
+
}
|
|
297
|
+
|
|
279
298
|
/** Extracts and stores contract data from a single block. */
|
|
280
299
|
private addContractDataToDb(block: L2Block): Promise<boolean> {
|
|
281
300
|
return this.updateContractDataOnDb(block, Operation.Store);
|
|
@@ -297,9 +316,6 @@ export class ArchiverDataStoreUpdater {
|
|
|
297
316
|
this.updatePublishedContractClasses(contractClassLogs, block.number, operation),
|
|
298
317
|
this.updateDeployedContractInstances(privateLogs, block.number, operation),
|
|
299
318
|
this.updateUpdatedContractInstances(publicLogs, block.header.globalVariables.timestamp, operation),
|
|
300
|
-
operation === Operation.Store
|
|
301
|
-
? this.storeBroadcastedIndividualFunctions(contractClassLogs, block.number)
|
|
302
|
-
: Promise.resolve(true),
|
|
303
319
|
])
|
|
304
320
|
).every(Boolean);
|
|
305
321
|
}
|
|
@@ -316,18 +332,37 @@ export class ArchiverDataStoreUpdater {
|
|
|
316
332
|
.filter(log => ContractClassPublishedEvent.isContractClassPublishedEvent(log))
|
|
317
333
|
.map(log => ContractClassPublishedEvent.fromLog(log));
|
|
318
334
|
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
contractClasses.
|
|
322
|
-
|
|
323
|
-
// TODO: Will probably want to create some worker threads to compute these bytecode commitments as they are expensive
|
|
324
|
-
const commitments = await Promise.all(
|
|
325
|
-
contractClasses.map(c => computePublicBytecodeCommitment(c.packedBytecode)),
|
|
326
|
-
);
|
|
327
|
-
return await this.store.addContractClasses(contractClasses, commitments, blockNum);
|
|
328
|
-
} else if (operation == Operation.Delete) {
|
|
335
|
+
if (operation == Operation.Delete) {
|
|
336
|
+
const contractClasses = contractClassPublishedEvents.map(e => e.toContractClassPublic());
|
|
337
|
+
if (contractClasses.length > 0) {
|
|
338
|
+
contractClasses.forEach(c => this.log.verbose(`${Operation[operation]} contract class ${c.id.toString()}`));
|
|
329
339
|
return await this.store.deleteContractClasses(contractClasses, blockNum);
|
|
330
340
|
}
|
|
341
|
+
return true;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
// Compute bytecode commitments and validate class IDs in a single pass.
|
|
345
|
+
const contractClasses: ContractClassPublicWithCommitment[] = [];
|
|
346
|
+
for (const event of contractClassPublishedEvents) {
|
|
347
|
+
const contractClass = await event.toContractClassPublicWithBytecodeCommitment();
|
|
348
|
+
const computedClassId = await computeContractClassId({
|
|
349
|
+
artifactHash: contractClass.artifactHash,
|
|
350
|
+
privateFunctionsRoot: contractClass.privateFunctionsRoot,
|
|
351
|
+
publicBytecodeCommitment: contractClass.publicBytecodeCommitment,
|
|
352
|
+
});
|
|
353
|
+
if (!computedClassId.equals(contractClass.id)) {
|
|
354
|
+
this.log.warn(
|
|
355
|
+
`Skipping contract class with mismatched id at block ${blockNum}. Claimed ${contractClass.id}, computed ${computedClassId}`,
|
|
356
|
+
{ blockNum, contractClassId: event.contractClassId.toString() },
|
|
357
|
+
);
|
|
358
|
+
continue;
|
|
359
|
+
}
|
|
360
|
+
contractClasses.push(contractClass);
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
if (contractClasses.length > 0) {
|
|
364
|
+
contractClasses.forEach(c => this.log.verbose(`${Operation[operation]} contract class ${c.id.toString()}`));
|
|
365
|
+
return await this.store.addContractClasses(contractClasses, blockNum);
|
|
331
366
|
}
|
|
332
367
|
return true;
|
|
333
368
|
}
|
|
@@ -340,10 +375,27 @@ export class ArchiverDataStoreUpdater {
|
|
|
340
375
|
blockNum: BlockNumber,
|
|
341
376
|
operation: Operation,
|
|
342
377
|
): Promise<boolean> {
|
|
343
|
-
const
|
|
378
|
+
const allInstances = allLogs
|
|
344
379
|
.filter(log => ContractInstancePublishedEvent.isContractInstancePublishedEvent(log))
|
|
345
380
|
.map(log => ContractInstancePublishedEvent.fromLog(log))
|
|
346
381
|
.map(e => e.toContractInstance());
|
|
382
|
+
|
|
383
|
+
// Verify that each instance's address matches the one derived from its fields if we're adding
|
|
384
|
+
const contractInstances =
|
|
385
|
+
operation === Operation.Delete
|
|
386
|
+
? allInstances
|
|
387
|
+
: await filterAsync(allInstances, async instance => {
|
|
388
|
+
const computedAddress = await computeContractAddressFromInstance(instance);
|
|
389
|
+
if (!computedAddress.equals(instance.address)) {
|
|
390
|
+
this.log.warn(
|
|
391
|
+
`Found contract instance with mismatched address at block ${blockNum}. Claimed ${instance.address} but computed ${computedAddress}.`,
|
|
392
|
+
{ instanceAddress: instance.address.toString(), computedAddress: computedAddress.toString(), blockNum },
|
|
393
|
+
);
|
|
394
|
+
return false;
|
|
395
|
+
}
|
|
396
|
+
return true;
|
|
397
|
+
});
|
|
398
|
+
|
|
347
399
|
if (contractInstances.length > 0) {
|
|
348
400
|
contractInstances.forEach(c =>
|
|
349
401
|
this.log.verbose(`${Operation[operation]} contract instance at ${c.address.toString()}`),
|
|
@@ -382,67 +434,4 @@ export class ArchiverDataStoreUpdater {
|
|
|
382
434
|
}
|
|
383
435
|
return true;
|
|
384
436
|
}
|
|
385
|
-
|
|
386
|
-
/**
|
|
387
|
-
* Stores the functions that were broadcasted individually.
|
|
388
|
-
*
|
|
389
|
-
* @dev Beware that there is not a delete variant of this, since they are added to contract classes
|
|
390
|
-
* and will be deleted as part of the class if needed.
|
|
391
|
-
*/
|
|
392
|
-
private async storeBroadcastedIndividualFunctions(
|
|
393
|
-
allLogs: ContractClassLog[],
|
|
394
|
-
_blockNum: BlockNumber,
|
|
395
|
-
): Promise<boolean> {
|
|
396
|
-
// Filter out private and utility function broadcast events
|
|
397
|
-
const privateFnEvents = allLogs
|
|
398
|
-
.filter(log => PrivateFunctionBroadcastedEvent.isPrivateFunctionBroadcastedEvent(log))
|
|
399
|
-
.map(log => PrivateFunctionBroadcastedEvent.fromLog(log));
|
|
400
|
-
const utilityFnEvents = allLogs
|
|
401
|
-
.filter(log => UtilityFunctionBroadcastedEvent.isUtilityFunctionBroadcastedEvent(log))
|
|
402
|
-
.map(log => UtilityFunctionBroadcastedEvent.fromLog(log));
|
|
403
|
-
|
|
404
|
-
// Group all events by contract class id
|
|
405
|
-
for (const [classIdString, classEvents] of Object.entries(
|
|
406
|
-
groupBy([...privateFnEvents, ...utilityFnEvents], e => e.contractClassId.toString()),
|
|
407
|
-
)) {
|
|
408
|
-
const contractClassId = Fr.fromHexString(classIdString);
|
|
409
|
-
const contractClass = await this.store.getContractClass(contractClassId);
|
|
410
|
-
if (!contractClass) {
|
|
411
|
-
this.log.warn(`Skipping broadcasted functions as contract class ${contractClassId.toString()} was not found`);
|
|
412
|
-
continue;
|
|
413
|
-
}
|
|
414
|
-
|
|
415
|
-
// Split private and utility functions, and filter out invalid ones
|
|
416
|
-
const allFns = classEvents.map(e => e.toFunctionWithMembershipProof());
|
|
417
|
-
const privateFns = allFns.filter(
|
|
418
|
-
(fn): fn is ExecutablePrivateFunctionWithMembershipProof => 'utilityFunctionsTreeRoot' in fn,
|
|
419
|
-
);
|
|
420
|
-
const utilityFns = allFns.filter(
|
|
421
|
-
(fn): fn is UtilityFunctionWithMembershipProof => 'privateFunctionsArtifactTreeRoot' in fn,
|
|
422
|
-
);
|
|
423
|
-
|
|
424
|
-
const privateFunctionsWithValidity = await Promise.all(
|
|
425
|
-
privateFns.map(async fn => ({ fn, valid: await isValidPrivateFunctionMembershipProof(fn, contractClass) })),
|
|
426
|
-
);
|
|
427
|
-
const validPrivateFns = privateFunctionsWithValidity.filter(({ valid }) => valid).map(({ fn }) => fn);
|
|
428
|
-
const utilityFunctionsWithValidity = await Promise.all(
|
|
429
|
-
utilityFns.map(async fn => ({
|
|
430
|
-
fn,
|
|
431
|
-
valid: await isValidUtilityFunctionMembershipProof(fn, contractClass),
|
|
432
|
-
})),
|
|
433
|
-
);
|
|
434
|
-
const validUtilityFns = utilityFunctionsWithValidity.filter(({ valid }) => valid).map(({ fn }) => fn);
|
|
435
|
-
const validFnCount = validPrivateFns.length + validUtilityFns.length;
|
|
436
|
-
if (validFnCount !== allFns.length) {
|
|
437
|
-
this.log.warn(`Skipping ${allFns.length - validFnCount} invalid functions`);
|
|
438
|
-
}
|
|
439
|
-
|
|
440
|
-
// Store the functions in the contract class in a single operation
|
|
441
|
-
if (validFnCount > 0) {
|
|
442
|
-
this.log.verbose(`Storing ${validFnCount} functions for contract class ${contractClassId.toString()}`);
|
|
443
|
-
}
|
|
444
|
-
return await this.store.addFunctions(contractClassId, validPrivateFns, validUtilityFns);
|
|
445
|
-
}
|
|
446
|
-
return true;
|
|
447
|
-
}
|
|
448
437
|
}
|
|
@@ -1,6 +1,9 @@
|
|
|
1
|
+
import type { SlotNumber } from '@aztec/foundation/branded-types';
|
|
1
2
|
import { createLogger } from '@aztec/foundation/log';
|
|
2
3
|
import type { L2Block } from '@aztec/stdlib/block';
|
|
3
4
|
import type { CheckpointData } from '@aztec/stdlib/checkpoint';
|
|
5
|
+
import type { L1RollupConstants } from '@aztec/stdlib/epoch-helpers';
|
|
6
|
+
import { getTimestampForSlot } from '@aztec/stdlib/epoch-helpers';
|
|
4
7
|
import {
|
|
5
8
|
Attributes,
|
|
6
9
|
type Gauge,
|
|
@@ -29,6 +32,7 @@ export class ArchiverInstrumentation {
|
|
|
29
32
|
private pruneCount: UpDownCounter;
|
|
30
33
|
|
|
31
34
|
private syncDurationPerBlock: Histogram;
|
|
35
|
+
private syncDurationPerCheckpoint: Histogram;
|
|
32
36
|
private syncBlockCount: UpDownCounter;
|
|
33
37
|
private manaPerBlock: Histogram;
|
|
34
38
|
private txsPerBlock: Histogram;
|
|
@@ -38,6 +42,8 @@ export class ArchiverInstrumentation {
|
|
|
38
42
|
|
|
39
43
|
private blockProposalTxTargetCount: UpDownCounter;
|
|
40
44
|
|
|
45
|
+
private checkpointL1InclusionDelay: Histogram;
|
|
46
|
+
|
|
41
47
|
private log = createLogger('archiver:instrumentation');
|
|
42
48
|
|
|
43
49
|
private constructor(
|
|
@@ -63,6 +69,8 @@ export class ArchiverInstrumentation {
|
|
|
63
69
|
|
|
64
70
|
this.syncDurationPerBlock = meter.createHistogram(Metrics.ARCHIVER_SYNC_PER_BLOCK);
|
|
65
71
|
|
|
72
|
+
this.syncDurationPerCheckpoint = meter.createHistogram(Metrics.ARCHIVER_SYNC_PER_CHECKPOINT);
|
|
73
|
+
|
|
66
74
|
this.syncBlockCount = createUpDownCounterWithDefault(meter, Metrics.ARCHIVER_SYNC_BLOCK_COUNT);
|
|
67
75
|
|
|
68
76
|
this.manaPerBlock = meter.createHistogram(Metrics.ARCHIVER_MANA_PER_BLOCK);
|
|
@@ -85,6 +93,8 @@ export class ArchiverInstrumentation {
|
|
|
85
93
|
},
|
|
86
94
|
);
|
|
87
95
|
|
|
96
|
+
this.checkpointL1InclusionDelay = meter.createHistogram(Metrics.ARCHIVER_CHECKPOINT_L1_INCLUSION_DELAY);
|
|
97
|
+
|
|
88
98
|
this.dbMetrics = new LmdbMetrics(
|
|
89
99
|
meter,
|
|
90
100
|
{
|
|
@@ -106,17 +116,26 @@ export class ArchiverInstrumentation {
|
|
|
106
116
|
return this.telemetry.isEnabled();
|
|
107
117
|
}
|
|
108
118
|
|
|
109
|
-
public
|
|
119
|
+
public processNewProposedBlock(syncTimePerBlock: number, block: L2Block) {
|
|
120
|
+
const attrs = { [Attributes.STATUS]: 'proposed' };
|
|
121
|
+
this.blockHeight.record(block.number, attrs);
|
|
110
122
|
this.syncDurationPerBlock.record(Math.ceil(syncTimePerBlock));
|
|
123
|
+
|
|
124
|
+
// Per block metrics
|
|
125
|
+
this.txCount.add(block.body.txEffects.length);
|
|
126
|
+
this.txsPerBlock.record(block.body.txEffects.length);
|
|
127
|
+
this.manaPerBlock.record(block.header.totalManaUsed.toNumber() / 1e6);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
public processNewCheckpointedBlocks(syncTimePerCheckpoint: number, blocks: L2Block[]) {
|
|
131
|
+
if (blocks.length === 0) {
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
this.syncDurationPerCheckpoint.record(Math.ceil(syncTimePerCheckpoint));
|
|
111
136
|
this.blockHeight.record(Math.max(...blocks.map(b => b.number)));
|
|
112
137
|
this.checkpointHeight.record(Math.max(...blocks.map(b => b.checkpointNumber)));
|
|
113
138
|
this.syncBlockCount.add(blocks.length);
|
|
114
|
-
|
|
115
|
-
for (const block of blocks) {
|
|
116
|
-
this.txCount.add(block.body.txEffects.length);
|
|
117
|
-
this.txsPerBlock.record(block.body.txEffects.length);
|
|
118
|
-
this.manaPerBlock.record(block.header.totalManaUsed.toNumber() / 1e6);
|
|
119
|
-
}
|
|
120
139
|
}
|
|
121
140
|
|
|
122
141
|
public processNewMessages(count: number, syncPerMessageMs: number) {
|
|
@@ -161,4 +180,17 @@ export class ArchiverInstrumentation {
|
|
|
161
180
|
[Attributes.L1_BLOCK_PROPOSAL_USED_TRACE]: usedTrace,
|
|
162
181
|
});
|
|
163
182
|
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Records L1 inclusion timing for a checkpoint observed on L1 (seconds into the L2 slot).
|
|
186
|
+
*/
|
|
187
|
+
public processCheckpointL1Timing(data: {
|
|
188
|
+
slotNumber: SlotNumber;
|
|
189
|
+
l1Timestamp: bigint;
|
|
190
|
+
l1Constants: Pick<L1RollupConstants, 'l1GenesisTime' | 'slotDuration'>;
|
|
191
|
+
}): void {
|
|
192
|
+
const slotStartTs = getTimestampForSlot(data.slotNumber, data.l1Constants);
|
|
193
|
+
const inclusionDelaySeconds = Number(data.l1Timestamp - slotStartTs);
|
|
194
|
+
this.checkpointL1InclusionDelay.record(inclusionDelaySeconds);
|
|
195
|
+
}
|
|
164
196
|
}
|