@aztec/archiver 0.0.1-commit.1bea0213 → 0.0.1-commit.217f559981
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.d.ts +7 -3
- package/dest/archiver.d.ts.map +1 -1
- package/dest/archiver.js +24 -93
- package/dest/factory.d.ts +3 -1
- package/dest/factory.d.ts.map +1 -1
- package/dest/factory.js +11 -7
- package/dest/index.d.ts +2 -1
- package/dest/index.d.ts.map +1 -1
- package/dest/index.js +1 -0
- package/dest/l1/bin/retrieve-calldata.js +18 -19
- package/dest/l1/calldata_retriever.d.ts +7 -1
- package/dest/l1/calldata_retriever.d.ts.map +1 -1
- package/dest/l1/calldata_retriever.js +17 -4
- package/dest/l1/data_retrieval.d.ts +3 -2
- package/dest/l1/data_retrieval.d.ts.map +1 -1
- package/dest/l1/data_retrieval.js +4 -3
- package/dest/l1/validate_trace.d.ts +6 -3
- package/dest/l1/validate_trace.d.ts.map +1 -1
- package/dest/l1/validate_trace.js +13 -9
- package/dest/modules/data_source_base.d.ts +11 -6
- package/dest/modules/data_source_base.d.ts.map +1 -1
- package/dest/modules/data_source_base.js +28 -72
- package/dest/modules/data_store_updater.d.ts +9 -2
- package/dest/modules/data_store_updater.d.ts.map +1 -1
- package/dest/modules/data_store_updater.js +40 -19
- package/dest/modules/instrumentation.d.ts +4 -2
- package/dest/modules/instrumentation.d.ts.map +1 -1
- package/dest/modules/instrumentation.js +26 -12
- package/dest/modules/l1_synchronizer.d.ts +3 -2
- package/dest/modules/l1_synchronizer.d.ts.map +1 -1
- package/dest/modules/l1_synchronizer.js +8 -9
- package/dest/store/block_store.d.ts +19 -15
- package/dest/store/block_store.d.ts.map +1 -1
- package/dest/store/block_store.js +71 -19
- package/dest/store/contract_class_store.d.ts +1 -1
- package/dest/store/contract_class_store.d.ts.map +1 -1
- package/dest/store/contract_class_store.js +11 -7
- package/dest/store/kv_archiver_store.d.ts +21 -7
- package/dest/store/kv_archiver_store.d.ts.map +1 -1
- package/dest/store/kv_archiver_store.js +20 -3
- package/dest/store/l2_tips_cache.d.ts +19 -0
- package/dest/store/l2_tips_cache.d.ts.map +1 -0
- package/dest/store/l2_tips_cache.js +89 -0
- package/dest/store/log_store.d.ts +1 -1
- package/dest/store/log_store.d.ts.map +1 -1
- package/dest/store/log_store.js +56 -36
- package/dest/test/fake_l1_state.d.ts +4 -1
- package/dest/test/fake_l1_state.d.ts.map +1 -1
- package/dest/test/fake_l1_state.js +15 -9
- package/dest/test/index.js +3 -1
- package/dest/test/mock_archiver.d.ts +1 -1
- package/dest/test/mock_archiver.d.ts.map +1 -1
- package/dest/test/mock_archiver.js +3 -2
- package/dest/test/mock_l2_block_source.d.ts +21 -6
- package/dest/test/mock_l2_block_source.d.ts.map +1 -1
- package/dest/test/mock_l2_block_source.js +127 -84
- 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 +7 -5
- package/dest/test/noop_l1_archiver.d.ts +23 -0
- package/dest/test/noop_l1_archiver.d.ts.map +1 -0
- package/dest/test/noop_l1_archiver.js +68 -0
- package/package.json +14 -13
- package/src/archiver.ts +32 -112
- package/src/factory.ts +26 -11
- package/src/index.ts +1 -0
- package/src/l1/bin/retrieve-calldata.ts +17 -23
- package/src/l1/calldata_retriever.ts +25 -3
- package/src/l1/data_retrieval.ts +4 -1
- package/src/l1/validate_trace.ts +24 -6
- package/src/modules/data_source_base.ts +56 -95
- package/src/modules/data_store_updater.ts +43 -18
- package/src/modules/instrumentation.ts +24 -12
- package/src/modules/l1_synchronizer.ts +9 -8
- package/src/store/block_store.ts +87 -38
- package/src/store/contract_class_store.ts +11 -7
- package/src/store/kv_archiver_store.ts +40 -8
- package/src/store/l2_tips_cache.ts +89 -0
- package/src/store/log_store.ts +95 -33
- package/src/test/fake_l1_state.ts +17 -9
- package/src/test/index.ts +3 -0
- package/src/test/mock_archiver.ts +3 -2
- package/src/test/mock_l2_block_source.ts +163 -83
- package/src/test/mock_structs.ts +22 -6
- package/src/test/noop_l1_archiver.ts +109 -0
package/src/l1/validate_trace.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { ViemPublicDebugClient } from '@aztec/ethereum/types';
|
|
2
|
-
import { createLogger } from '@aztec/foundation/log';
|
|
2
|
+
import { type Logger, type LoggerBindings, createLogger } from '@aztec/foundation/log';
|
|
3
3
|
|
|
4
4
|
import type { Hex } from 'viem';
|
|
5
5
|
import type { ZodSchema } from 'zod';
|
|
@@ -7,8 +7,6 @@ import type { ZodSchema } from 'zod';
|
|
|
7
7
|
import { callTraceSchema } from './debug_tx.js';
|
|
8
8
|
import { traceTransactionResponseSchema } from './trace_tx.js';
|
|
9
9
|
|
|
10
|
-
const logger = createLogger('aztec:archiver:validate_trace');
|
|
11
|
-
|
|
12
10
|
/**
|
|
13
11
|
* Helper function to test a trace method with validation
|
|
14
12
|
*
|
|
@@ -17,6 +15,7 @@ const logger = createLogger('aztec:archiver:validate_trace');
|
|
|
17
15
|
* @param schema - Zod schema to validate the response
|
|
18
16
|
* @param method - Name of the RPC method ('debug_traceTransaction' or 'trace_transaction')
|
|
19
17
|
* @param blockType - Type of block being tested ('recent' or 'old')
|
|
18
|
+
* @param logger - Logger instance
|
|
20
19
|
* @returns true if the method works and validation passes, false otherwise
|
|
21
20
|
*/
|
|
22
21
|
async function testTraceMethod(
|
|
@@ -25,6 +24,7 @@ async function testTraceMethod(
|
|
|
25
24
|
schema: ZodSchema,
|
|
26
25
|
method: 'debug_traceTransaction' | 'trace_transaction',
|
|
27
26
|
blockType: string,
|
|
27
|
+
logger: Logger,
|
|
28
28
|
): Promise<boolean> {
|
|
29
29
|
try {
|
|
30
30
|
// Make request with appropriate params based on method name
|
|
@@ -59,9 +59,14 @@ export interface TraceAvailability {
|
|
|
59
59
|
* Validates the availability of debug/trace methods on the Ethereum client.
|
|
60
60
|
*
|
|
61
61
|
* @param client - The Viem public debug client
|
|
62
|
+
* @param bindings - Optional logger bindings for context
|
|
62
63
|
* @returns Object indicating which trace methods are available for recent and old blocks
|
|
63
64
|
*/
|
|
64
|
-
export async function validateTraceAvailability(
|
|
65
|
+
export async function validateTraceAvailability(
|
|
66
|
+
client: ViemPublicDebugClient,
|
|
67
|
+
bindings?: LoggerBindings,
|
|
68
|
+
): Promise<TraceAvailability> {
|
|
69
|
+
const logger = createLogger('archiver:validate_trace', bindings);
|
|
65
70
|
const result: TraceAvailability = {
|
|
66
71
|
debugTraceRecent: false,
|
|
67
72
|
traceTransactionRecent: false,
|
|
@@ -95,6 +100,7 @@ export async function validateTraceAvailability(client: ViemPublicDebugClient):
|
|
|
95
100
|
callTraceSchema,
|
|
96
101
|
'debug_traceTransaction',
|
|
97
102
|
'recent',
|
|
103
|
+
logger,
|
|
98
104
|
);
|
|
99
105
|
|
|
100
106
|
// Test trace_transaction with recent block
|
|
@@ -104,6 +110,7 @@ export async function validateTraceAvailability(client: ViemPublicDebugClient):
|
|
|
104
110
|
traceTransactionResponseSchema,
|
|
105
111
|
'trace_transaction',
|
|
106
112
|
'recent',
|
|
113
|
+
logger,
|
|
107
114
|
);
|
|
108
115
|
|
|
109
116
|
// Get a block from 512 blocks ago
|
|
@@ -132,7 +139,14 @@ export async function validateTraceAvailability(client: ViemPublicDebugClient):
|
|
|
132
139
|
const oldTxHash = oldBlock.transactions[0] as Hex;
|
|
133
140
|
|
|
134
141
|
// Test debug_traceTransaction with old block
|
|
135
|
-
result.debugTraceOld = await testTraceMethod(
|
|
142
|
+
result.debugTraceOld = await testTraceMethod(
|
|
143
|
+
client,
|
|
144
|
+
oldTxHash,
|
|
145
|
+
callTraceSchema,
|
|
146
|
+
'debug_traceTransaction',
|
|
147
|
+
'old',
|
|
148
|
+
logger,
|
|
149
|
+
);
|
|
136
150
|
|
|
137
151
|
// Test trace_transaction with old block
|
|
138
152
|
result.traceTransactionOld = await testTraceMethod(
|
|
@@ -141,6 +155,7 @@ export async function validateTraceAvailability(client: ViemPublicDebugClient):
|
|
|
141
155
|
traceTransactionResponseSchema,
|
|
142
156
|
'trace_transaction',
|
|
143
157
|
'old',
|
|
158
|
+
logger,
|
|
144
159
|
);
|
|
145
160
|
} catch (error) {
|
|
146
161
|
logger.warn(`Error validating debug_traceTransaction and trace_transaction availability: ${error}`);
|
|
@@ -159,15 +174,18 @@ function hasTxs(block: { transactions?: Hex[] }): boolean {
|
|
|
159
174
|
*
|
|
160
175
|
* @param client - The Viem public debug client
|
|
161
176
|
* @param ethereumAllowNoDebugHosts - If false, throws an error when no trace methods are available
|
|
177
|
+
* @param bindings - Optional logger bindings for context
|
|
162
178
|
* @throws Error if ethereumAllowNoDebugHosts is false and no trace methods are available
|
|
163
179
|
*/
|
|
164
180
|
export async function validateAndLogTraceAvailability(
|
|
165
181
|
client: ViemPublicDebugClient,
|
|
166
182
|
ethereumAllowNoDebugHosts: boolean,
|
|
183
|
+
bindings?: LoggerBindings,
|
|
167
184
|
): Promise<void> {
|
|
185
|
+
const logger = createLogger('archiver:validate_trace', bindings);
|
|
168
186
|
logger.debug('Validating trace/debug method availability...');
|
|
169
187
|
|
|
170
|
-
const availability = await validateTraceAvailability(client);
|
|
188
|
+
const availability = await validateTraceAvailability(client, bindings);
|
|
171
189
|
|
|
172
190
|
// Check if we have support for old blocks (either debug or trace)
|
|
173
191
|
const hasOldBlockSupport = availability.debugTraceOld || availability.traceTransactionOld;
|
|
@@ -1,11 +1,12 @@
|
|
|
1
|
+
import { range } from '@aztec/foundation/array';
|
|
1
2
|
import { BlockNumber, CheckpointNumber, type EpochNumber, type SlotNumber } from '@aztec/foundation/branded-types';
|
|
2
3
|
import type { Fr } from '@aztec/foundation/curves/bn254';
|
|
3
4
|
import type { EthAddress } from '@aztec/foundation/eth-address';
|
|
4
5
|
import { isDefined } from '@aztec/foundation/types';
|
|
5
6
|
import type { FunctionSelector } from '@aztec/stdlib/abi';
|
|
6
7
|
import type { AztecAddress } from '@aztec/stdlib/aztec-address';
|
|
7
|
-
import {
|
|
8
|
-
import { Checkpoint, PublishedCheckpoint } from '@aztec/stdlib/checkpoint';
|
|
8
|
+
import { type BlockData, type BlockHash, CheckpointedL2Block, L2Block, type L2Tips } from '@aztec/stdlib/block';
|
|
9
|
+
import { Checkpoint, type CheckpointData, PublishedCheckpoint } from '@aztec/stdlib/checkpoint';
|
|
9
10
|
import type { ContractClassPublic, ContractDataSource, ContractInstanceWithAddress } from '@aztec/stdlib/contract';
|
|
10
11
|
import { type L1RollupConstants, getSlotRangeForEpoch } from '@aztec/stdlib/epoch-helpers';
|
|
11
12
|
import type { GetContractClassLogsResponse, GetPublicLogsResponse } from '@aztec/stdlib/interfaces/client';
|
|
@@ -17,7 +18,6 @@ import type { BlockHeader, IndexedTxEffect, TxHash, TxReceipt } from '@aztec/std
|
|
|
17
18
|
import type { UInt64 } from '@aztec/stdlib/types';
|
|
18
19
|
|
|
19
20
|
import type { ArchiverDataSource } from '../interfaces.js';
|
|
20
|
-
import type { CheckpointData } from '../store/block_store.js';
|
|
21
21
|
import type { KVArchiverDataStore } from '../store/kv_archiver_store.js';
|
|
22
22
|
import type { ValidateCheckpointResult } from './validation.js';
|
|
23
23
|
|
|
@@ -114,14 +114,14 @@ export abstract class ArchiverDataSourceBase
|
|
|
114
114
|
if (!checkpointData) {
|
|
115
115
|
return undefined;
|
|
116
116
|
}
|
|
117
|
-
return BlockNumber(checkpointData.startBlock + checkpointData.
|
|
117
|
+
return BlockNumber(checkpointData.startBlock + checkpointData.blockCount - 1);
|
|
118
118
|
}
|
|
119
119
|
|
|
120
120
|
public getCheckpointedBlocks(from: BlockNumber, limit: number): Promise<CheckpointedL2Block[]> {
|
|
121
121
|
return this.store.getCheckpointedBlocks(from, limit);
|
|
122
122
|
}
|
|
123
123
|
|
|
124
|
-
public getBlockHeaderByHash(blockHash:
|
|
124
|
+
public getBlockHeaderByHash(blockHash: BlockHash): Promise<BlockHeader | undefined> {
|
|
125
125
|
return this.store.getBlockHeaderByHash(blockHash);
|
|
126
126
|
}
|
|
127
127
|
|
|
@@ -129,6 +129,14 @@ export abstract class ArchiverDataSourceBase
|
|
|
129
129
|
return this.store.getBlockHeaderByArchive(archive);
|
|
130
130
|
}
|
|
131
131
|
|
|
132
|
+
public getBlockData(number: BlockNumber): Promise<BlockData | undefined> {
|
|
133
|
+
return this.store.getBlockData(number);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
public getBlockDataByArchive(archive: Fr): Promise<BlockData | undefined> {
|
|
137
|
+
return this.store.getBlockDataByArchive(archive);
|
|
138
|
+
}
|
|
139
|
+
|
|
132
140
|
public async getL2Block(number: BlockNumber): Promise<L2Block | undefined> {
|
|
133
141
|
// If the number provided is -ve, then return the latest block.
|
|
134
142
|
if (number < 0) {
|
|
@@ -223,28 +231,21 @@ export abstract class ArchiverDataSourceBase
|
|
|
223
231
|
|
|
224
232
|
public async getCheckpoints(checkpointNumber: CheckpointNumber, limit: number): Promise<PublishedCheckpoint[]> {
|
|
225
233
|
const checkpoints = await this.store.getRangeOfCheckpoints(checkpointNumber, limit);
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
const
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
const checkpoint = checkpoints[i];
|
|
234
|
-
const fullCheckpoint = new Checkpoint(
|
|
235
|
-
checkpoint.archive,
|
|
236
|
-
checkpoint.header,
|
|
237
|
-
blocksForCheckpoint,
|
|
238
|
-
checkpoint.checkpointNumber,
|
|
239
|
-
);
|
|
240
|
-
const publishedCheckpoint = new PublishedCheckpoint(
|
|
241
|
-
fullCheckpoint,
|
|
242
|
-
checkpoint.l1,
|
|
243
|
-
checkpoint.attestations.map(x => CommitteeAttestation.fromBuffer(x)),
|
|
244
|
-
);
|
|
245
|
-
fullCheckpoints.push(publishedCheckpoint);
|
|
234
|
+
return Promise.all(checkpoints.map(ch => this.getPublishedCheckpointFromCheckpointData(ch)));
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
private async getPublishedCheckpointFromCheckpointData(checkpoint: CheckpointData): Promise<PublishedCheckpoint> {
|
|
238
|
+
const blocksForCheckpoint = await this.store.getBlocksForCheckpoint(checkpoint.checkpointNumber);
|
|
239
|
+
if (!blocksForCheckpoint) {
|
|
240
|
+
throw new Error(`Blocks for checkpoint ${checkpoint.checkpointNumber} not found`);
|
|
246
241
|
}
|
|
247
|
-
|
|
242
|
+
const fullCheckpoint = new Checkpoint(
|
|
243
|
+
checkpoint.archive,
|
|
244
|
+
checkpoint.header,
|
|
245
|
+
blocksForCheckpoint,
|
|
246
|
+
checkpoint.checkpointNumber,
|
|
247
|
+
);
|
|
248
|
+
return new PublishedCheckpoint(fullCheckpoint, checkpoint.l1, checkpoint.attestations);
|
|
248
249
|
}
|
|
249
250
|
|
|
250
251
|
public getBlocksForSlot(slotNumber: SlotNumber): Promise<L2Block[]> {
|
|
@@ -252,84 +253,44 @@ export abstract class ArchiverDataSourceBase
|
|
|
252
253
|
}
|
|
253
254
|
|
|
254
255
|
public async getCheckpointedBlocksForEpoch(epochNumber: EpochNumber): Promise<CheckpointedL2Block[]> {
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
let checkpoint = await this.store.getCheckpointData(await this.store.getSynchedCheckpointNumber());
|
|
265
|
-
const slot = (b: CheckpointData) => b.header.slotNumber;
|
|
266
|
-
while (checkpoint && slot(checkpoint) >= start) {
|
|
267
|
-
if (slot(checkpoint) <= end) {
|
|
268
|
-
// push the blocks on backwards
|
|
269
|
-
const endBlock = checkpoint.startBlock + checkpoint.numBlocks - 1;
|
|
270
|
-
for (let i = endBlock; i >= checkpoint.startBlock; i--) {
|
|
271
|
-
const checkpointedBlock = await this.getCheckpointedBlock(BlockNumber(i));
|
|
272
|
-
if (checkpointedBlock) {
|
|
273
|
-
blocks.push(checkpointedBlock);
|
|
274
|
-
}
|
|
275
|
-
}
|
|
276
|
-
}
|
|
277
|
-
checkpoint = await this.store.getCheckpointData(CheckpointNumber(checkpoint.checkpointNumber - 1));
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
return blocks.reverse();
|
|
256
|
+
const checkpointsData = await this.getCheckpointsDataForEpoch(epochNumber);
|
|
257
|
+
const blocks = await Promise.all(
|
|
258
|
+
checkpointsData.flatMap(checkpoint =>
|
|
259
|
+
range(checkpoint.blockCount, checkpoint.startBlock).map(blockNumber =>
|
|
260
|
+
this.getCheckpointedBlock(BlockNumber(blockNumber)),
|
|
261
|
+
),
|
|
262
|
+
),
|
|
263
|
+
);
|
|
264
|
+
return blocks.filter(isDefined);
|
|
281
265
|
}
|
|
282
266
|
|
|
283
267
|
public async getCheckpointedBlockHeadersForEpoch(epochNumber: EpochNumber): Promise<BlockHeader[]> {
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
let checkpoint = await this.store.getCheckpointData(await this.store.getSynchedCheckpointNumber());
|
|
294
|
-
const slot = (b: CheckpointData) => b.header.slotNumber;
|
|
295
|
-
while (checkpoint && slot(checkpoint) >= start) {
|
|
296
|
-
if (slot(checkpoint) <= end) {
|
|
297
|
-
// push the blocks on backwards
|
|
298
|
-
const endBlock = checkpoint.startBlock + checkpoint.numBlocks - 1;
|
|
299
|
-
for (let i = endBlock; i >= checkpoint.startBlock; i--) {
|
|
300
|
-
const block = await this.getBlockHeader(BlockNumber(i));
|
|
301
|
-
if (block) {
|
|
302
|
-
blocks.push(block);
|
|
303
|
-
}
|
|
304
|
-
}
|
|
305
|
-
}
|
|
306
|
-
checkpoint = await this.store.getCheckpointData(CheckpointNumber(checkpoint.checkpointNumber - 1));
|
|
307
|
-
}
|
|
308
|
-
return blocks.reverse();
|
|
268
|
+
const checkpointsData = await this.getCheckpointsDataForEpoch(epochNumber);
|
|
269
|
+
const blocks = await Promise.all(
|
|
270
|
+
checkpointsData.flatMap(checkpoint =>
|
|
271
|
+
range(checkpoint.blockCount, checkpoint.startBlock).map(blockNumber =>
|
|
272
|
+
this.getBlockHeader(BlockNumber(blockNumber)),
|
|
273
|
+
),
|
|
274
|
+
),
|
|
275
|
+
);
|
|
276
|
+
return blocks.filter(isDefined);
|
|
309
277
|
}
|
|
310
278
|
|
|
311
279
|
public async getCheckpointsForEpoch(epochNumber: EpochNumber): Promise<Checkpoint[]> {
|
|
280
|
+
const checkpointsData = await this.getCheckpointsDataForEpoch(epochNumber);
|
|
281
|
+
return Promise.all(
|
|
282
|
+
checkpointsData.map(data => this.getPublishedCheckpointFromCheckpointData(data).then(p => p.checkpoint)),
|
|
283
|
+
);
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
/** Returns checkpoint data for all checkpoints whose slot falls within the given epoch. */
|
|
287
|
+
public getCheckpointsDataForEpoch(epochNumber: EpochNumber): Promise<CheckpointData[]> {
|
|
312
288
|
if (!this.l1Constants) {
|
|
313
289
|
throw new Error('L1 constants not set');
|
|
314
290
|
}
|
|
315
291
|
|
|
316
292
|
const [start, end] = getSlotRangeForEpoch(epochNumber, this.l1Constants);
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
// Walk the list of checkpoints backwards and filter by slots matching the requested epoch.
|
|
320
|
-
// We'll typically ask for checkpoints for a very recent epoch, so we shouldn't need an index here.
|
|
321
|
-
let checkpointData = await this.store.getCheckpointData(await this.store.getSynchedCheckpointNumber());
|
|
322
|
-
const slot = (b: CheckpointData) => b.header.slotNumber;
|
|
323
|
-
while (checkpointData && slot(checkpointData) >= start) {
|
|
324
|
-
if (slot(checkpointData) <= end) {
|
|
325
|
-
// push the checkpoints on backwards
|
|
326
|
-
const [checkpoint] = await this.getCheckpoints(checkpointData.checkpointNumber, 1);
|
|
327
|
-
checkpoints.push(checkpoint.checkpoint);
|
|
328
|
-
}
|
|
329
|
-
checkpointData = await this.store.getCheckpointData(CheckpointNumber(checkpointData.checkpointNumber - 1));
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
return checkpoints.reverse();
|
|
293
|
+
return this.store.getCheckpointDataForSlotRange(start, end);
|
|
333
294
|
}
|
|
334
295
|
|
|
335
296
|
public async getBlock(number: BlockNumber): Promise<L2Block | undefined> {
|
|
@@ -347,7 +308,7 @@ export abstract class ArchiverDataSourceBase
|
|
|
347
308
|
return this.store.getBlocks(from, limit);
|
|
348
309
|
}
|
|
349
310
|
|
|
350
|
-
public getCheckpointedBlockByHash(blockHash:
|
|
311
|
+
public getCheckpointedBlockByHash(blockHash: BlockHash): Promise<CheckpointedL2Block | undefined> {
|
|
351
312
|
return this.store.getCheckpointedBlockByHash(blockHash);
|
|
352
313
|
}
|
|
353
314
|
|
|
@@ -355,7 +316,7 @@ export abstract class ArchiverDataSourceBase
|
|
|
355
316
|
return this.store.getCheckpointedBlockByArchive(archive);
|
|
356
317
|
}
|
|
357
318
|
|
|
358
|
-
public async getL2BlockByHash(blockHash:
|
|
319
|
+
public async getL2BlockByHash(blockHash: BlockHash): Promise<L2Block | undefined> {
|
|
359
320
|
const checkpointedBlock = await this.store.getCheckpointedBlockByHash(blockHash);
|
|
360
321
|
return checkpointedBlock?.block;
|
|
361
322
|
}
|
|
@@ -25,6 +25,7 @@ import type { UInt64 } from '@aztec/stdlib/types';
|
|
|
25
25
|
import groupBy from 'lodash.groupby';
|
|
26
26
|
|
|
27
27
|
import type { KVArchiverDataStore } from '../store/kv_archiver_store.js';
|
|
28
|
+
import type { L2TipsCache } from '../store/l2_tips_cache.js';
|
|
28
29
|
|
|
29
30
|
/** Operation type for contract data updates. */
|
|
30
31
|
enum Operation {
|
|
@@ -44,7 +45,10 @@ type ReconcileCheckpointsResult = {
|
|
|
44
45
|
export class ArchiverDataStoreUpdater {
|
|
45
46
|
private readonly log = createLogger('archiver:store_updater');
|
|
46
47
|
|
|
47
|
-
constructor(
|
|
48
|
+
constructor(
|
|
49
|
+
private store: KVArchiverDataStore,
|
|
50
|
+
private l2TipsCache?: L2TipsCache,
|
|
51
|
+
) {}
|
|
48
52
|
|
|
49
53
|
/**
|
|
50
54
|
* Adds proposed blocks to the store with contract class/instance extraction from logs.
|
|
@@ -56,11 +60,11 @@ export class ArchiverDataStoreUpdater {
|
|
|
56
60
|
* @param pendingChainValidationStatus - Optional validation status to set.
|
|
57
61
|
* @returns True if the operation is successful.
|
|
58
62
|
*/
|
|
59
|
-
public addProposedBlocks(
|
|
63
|
+
public async addProposedBlocks(
|
|
60
64
|
blocks: L2Block[],
|
|
61
65
|
pendingChainValidationStatus?: ValidateCheckpointResult,
|
|
62
66
|
): Promise<boolean> {
|
|
63
|
-
|
|
67
|
+
const result = await this.store.transactionAsync(async () => {
|
|
64
68
|
await this.store.addProposedBlocks(blocks);
|
|
65
69
|
|
|
66
70
|
const opResults = await Promise.all([
|
|
@@ -72,8 +76,10 @@ export class ArchiverDataStoreUpdater {
|
|
|
72
76
|
...blocks.map(block => this.addContractDataToDb(block)),
|
|
73
77
|
]);
|
|
74
78
|
|
|
79
|
+
await this.l2TipsCache?.refresh();
|
|
75
80
|
return opResults.every(Boolean);
|
|
76
81
|
});
|
|
82
|
+
return result;
|
|
77
83
|
}
|
|
78
84
|
|
|
79
85
|
/**
|
|
@@ -87,11 +93,11 @@ export class ArchiverDataStoreUpdater {
|
|
|
87
93
|
* @param pendingChainValidationStatus - Optional validation status to set.
|
|
88
94
|
* @returns Result with information about any pruned blocks.
|
|
89
95
|
*/
|
|
90
|
-
public addCheckpoints(
|
|
96
|
+
public async addCheckpoints(
|
|
91
97
|
checkpoints: PublishedCheckpoint[],
|
|
92
98
|
pendingChainValidationStatus?: ValidateCheckpointResult,
|
|
93
99
|
): Promise<ReconcileCheckpointsResult> {
|
|
94
|
-
|
|
100
|
+
const result = await this.store.transactionAsync(async () => {
|
|
95
101
|
// Before adding checkpoints, check for conflicts with local blocks if any
|
|
96
102
|
const { prunedBlocks, lastAlreadyInsertedBlockNumber } = await this.pruneMismatchingLocalBlocks(checkpoints);
|
|
97
103
|
|
|
@@ -111,8 +117,10 @@ export class ArchiverDataStoreUpdater {
|
|
|
111
117
|
...newBlocks.map(block => this.addContractDataToDb(block)),
|
|
112
118
|
]);
|
|
113
119
|
|
|
120
|
+
await this.l2TipsCache?.refresh();
|
|
114
121
|
return { prunedBlocks, lastAlreadyInsertedBlockNumber };
|
|
115
122
|
});
|
|
123
|
+
return result;
|
|
116
124
|
}
|
|
117
125
|
|
|
118
126
|
/**
|
|
@@ -197,8 +205,8 @@ export class ArchiverDataStoreUpdater {
|
|
|
197
205
|
* @returns The removed blocks.
|
|
198
206
|
* @throws Error if any block to be removed is checkpointed.
|
|
199
207
|
*/
|
|
200
|
-
public removeUncheckpointedBlocksAfter(blockNumber: BlockNumber): Promise<L2Block[]> {
|
|
201
|
-
|
|
208
|
+
public async removeUncheckpointedBlocksAfter(blockNumber: BlockNumber): Promise<L2Block[]> {
|
|
209
|
+
const result = await this.store.transactionAsync(async () => {
|
|
202
210
|
// Verify we're only removing uncheckpointed blocks
|
|
203
211
|
const lastCheckpointedBlockNumber = await this.store.getCheckpointedL2BlockNumber();
|
|
204
212
|
if (blockNumber < lastCheckpointedBlockNumber) {
|
|
@@ -207,8 +215,11 @@ export class ArchiverDataStoreUpdater {
|
|
|
207
215
|
);
|
|
208
216
|
}
|
|
209
217
|
|
|
210
|
-
|
|
218
|
+
const result = await this.removeBlocksAfter(blockNumber);
|
|
219
|
+
await this.l2TipsCache?.refresh();
|
|
220
|
+
return result;
|
|
211
221
|
});
|
|
222
|
+
return result;
|
|
212
223
|
}
|
|
213
224
|
|
|
214
225
|
/**
|
|
@@ -238,17 +249,31 @@ export class ArchiverDataStoreUpdater {
|
|
|
238
249
|
* @returns True if the operation is successful.
|
|
239
250
|
*/
|
|
240
251
|
public async removeCheckpointsAfter(checkpointNumber: CheckpointNumber): Promise<boolean> {
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
252
|
+
return await this.store.transactionAsync(async () => {
|
|
253
|
+
const { blocksRemoved = [] } = await this.store.removeCheckpointsAfter(checkpointNumber);
|
|
254
|
+
|
|
255
|
+
const opResults = await Promise.all([
|
|
256
|
+
// Prune rolls back to the last proven block, which is by definition valid
|
|
257
|
+
this.store.setPendingChainValidationStatus({ valid: true }),
|
|
258
|
+
// Remove contract data for all blocks being removed
|
|
259
|
+
...blocksRemoved.map(block => this.removeContractDataFromDb(block)),
|
|
260
|
+
this.store.deleteLogs(blocksRemoved),
|
|
261
|
+
]);
|
|
250
262
|
|
|
251
|
-
|
|
263
|
+
await this.l2TipsCache?.refresh();
|
|
264
|
+
return opResults.every(Boolean);
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
/**
|
|
269
|
+
* Updates the proven checkpoint number and refreshes the L2 tips cache.
|
|
270
|
+
* @param checkpointNumber - The checkpoint number to set as proven.
|
|
271
|
+
*/
|
|
272
|
+
public async setProvenCheckpointNumber(checkpointNumber: CheckpointNumber): Promise<void> {
|
|
273
|
+
await this.store.transactionAsync(async () => {
|
|
274
|
+
await this.store.setProvenCheckpointNumber(checkpointNumber);
|
|
275
|
+
await this.l2TipsCache?.refresh();
|
|
276
|
+
});
|
|
252
277
|
}
|
|
253
278
|
|
|
254
279
|
/** Extracts and stores contract data from a single block. */
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { createLogger } from '@aztec/foundation/log';
|
|
2
2
|
import type { L2Block } from '@aztec/stdlib/block';
|
|
3
|
+
import type { CheckpointData } from '@aztec/stdlib/checkpoint';
|
|
3
4
|
import {
|
|
4
5
|
Attributes,
|
|
5
6
|
type Gauge,
|
|
@@ -10,12 +11,14 @@ import {
|
|
|
10
11
|
type TelemetryClient,
|
|
11
12
|
type Tracer,
|
|
12
13
|
type UpDownCounter,
|
|
14
|
+
createUpDownCounterWithDefault,
|
|
13
15
|
} from '@aztec/telemetry-client';
|
|
14
16
|
|
|
15
17
|
export class ArchiverInstrumentation {
|
|
16
18
|
public readonly tracer: Tracer;
|
|
17
19
|
|
|
18
20
|
private blockHeight: Gauge;
|
|
21
|
+
private checkpointHeight: Gauge;
|
|
19
22
|
private txCount: UpDownCounter;
|
|
20
23
|
private l1BlockHeight: Gauge;
|
|
21
24
|
private proofsSubmittedDelay: Histogram;
|
|
@@ -46,17 +49,21 @@ export class ArchiverInstrumentation {
|
|
|
46
49
|
|
|
47
50
|
this.blockHeight = meter.createGauge(Metrics.ARCHIVER_BLOCK_HEIGHT);
|
|
48
51
|
|
|
52
|
+
this.checkpointHeight = meter.createGauge(Metrics.ARCHIVER_CHECKPOINT_HEIGHT);
|
|
53
|
+
|
|
49
54
|
this.l1BlockHeight = meter.createGauge(Metrics.ARCHIVER_L1_BLOCK_HEIGHT);
|
|
50
55
|
|
|
51
|
-
this.txCount = meter
|
|
56
|
+
this.txCount = createUpDownCounterWithDefault(meter, Metrics.ARCHIVER_TOTAL_TXS);
|
|
52
57
|
|
|
53
|
-
this.proofsSubmittedCount = meter
|
|
58
|
+
this.proofsSubmittedCount = createUpDownCounterWithDefault(meter, Metrics.ARCHIVER_ROLLUP_PROOF_COUNT, {
|
|
59
|
+
[Attributes.PROOF_TIMED_OUT]: [true, false],
|
|
60
|
+
});
|
|
54
61
|
|
|
55
62
|
this.proofsSubmittedDelay = meter.createHistogram(Metrics.ARCHIVER_ROLLUP_PROOF_DELAY);
|
|
56
63
|
|
|
57
64
|
this.syncDurationPerBlock = meter.createHistogram(Metrics.ARCHIVER_SYNC_PER_BLOCK);
|
|
58
65
|
|
|
59
|
-
this.syncBlockCount = meter
|
|
66
|
+
this.syncBlockCount = createUpDownCounterWithDefault(meter, Metrics.ARCHIVER_SYNC_BLOCK_COUNT);
|
|
60
67
|
|
|
61
68
|
this.manaPerBlock = meter.createHistogram(Metrics.ARCHIVER_MANA_PER_BLOCK);
|
|
62
69
|
|
|
@@ -64,13 +71,19 @@ export class ArchiverInstrumentation {
|
|
|
64
71
|
|
|
65
72
|
this.syncDurationPerMessage = meter.createHistogram(Metrics.ARCHIVER_SYNC_PER_MESSAGE);
|
|
66
73
|
|
|
67
|
-
this.syncMessageCount = meter
|
|
74
|
+
this.syncMessageCount = createUpDownCounterWithDefault(meter, Metrics.ARCHIVER_SYNC_MESSAGE_COUNT);
|
|
68
75
|
|
|
69
76
|
this.pruneDuration = meter.createHistogram(Metrics.ARCHIVER_PRUNE_DURATION);
|
|
70
77
|
|
|
71
|
-
this.pruneCount = meter
|
|
78
|
+
this.pruneCount = createUpDownCounterWithDefault(meter, Metrics.ARCHIVER_PRUNE_COUNT);
|
|
72
79
|
|
|
73
|
-
this.blockProposalTxTargetCount =
|
|
80
|
+
this.blockProposalTxTargetCount = createUpDownCounterWithDefault(
|
|
81
|
+
meter,
|
|
82
|
+
Metrics.ARCHIVER_BLOCK_PROPOSAL_TX_TARGET_COUNT,
|
|
83
|
+
{
|
|
84
|
+
[Attributes.L1_BLOCK_PROPOSAL_USED_TRACE]: [true, false],
|
|
85
|
+
},
|
|
86
|
+
);
|
|
74
87
|
|
|
75
88
|
this.dbMetrics = new LmdbMetrics(
|
|
76
89
|
meter,
|
|
@@ -84,10 +97,6 @@ export class ArchiverInstrumentation {
|
|
|
84
97
|
public static async new(telemetry: TelemetryClient, lmdbStats?: LmdbStatsCallback) {
|
|
85
98
|
const instance = new ArchiverInstrumentation(telemetry, lmdbStats);
|
|
86
99
|
|
|
87
|
-
instance.syncBlockCount.add(0);
|
|
88
|
-
instance.syncMessageCount.add(0);
|
|
89
|
-
instance.pruneCount.add(0);
|
|
90
|
-
|
|
91
100
|
await instance.telemetry.flush();
|
|
92
101
|
|
|
93
102
|
return instance;
|
|
@@ -100,6 +109,7 @@ export class ArchiverInstrumentation {
|
|
|
100
109
|
public processNewBlocks(syncTimePerBlock: number, blocks: L2Block[]) {
|
|
101
110
|
this.syncDurationPerBlock.record(Math.ceil(syncTimePerBlock));
|
|
102
111
|
this.blockHeight.record(Math.max(...blocks.map(b => b.number)));
|
|
112
|
+
this.checkpointHeight.record(Math.max(...blocks.map(b => b.checkpointNumber)));
|
|
103
113
|
this.syncBlockCount.add(blocks.length);
|
|
104
114
|
|
|
105
115
|
for (const block of blocks) {
|
|
@@ -122,8 +132,10 @@ export class ArchiverInstrumentation {
|
|
|
122
132
|
this.pruneDuration.record(Math.ceil(duration));
|
|
123
133
|
}
|
|
124
134
|
|
|
125
|
-
public
|
|
126
|
-
|
|
135
|
+
public updateLastProvenCheckpoint(checkpoint: CheckpointData) {
|
|
136
|
+
const lastBlockNumberInCheckpoint = checkpoint.startBlock + checkpoint.blockCount - 1;
|
|
137
|
+
this.blockHeight.record(lastBlockNumberInCheckpoint, { [Attributes.STATUS]: 'proven' });
|
|
138
|
+
this.checkpointHeight.record(checkpoint.checkpointNumber, { [Attributes.STATUS]: 'proven' });
|
|
127
139
|
}
|
|
128
140
|
|
|
129
141
|
public processProofsVerified(logs: { proverId: string; l2BlockNumber: bigint; delay: bigint }[]) {
|
|
@@ -16,7 +16,7 @@ import { DateProvider, Timer, elapsed } from '@aztec/foundation/timer';
|
|
|
16
16
|
import { isDefined } from '@aztec/foundation/types';
|
|
17
17
|
import { type ArchiverEmitter, L2BlockSourceEvents, type ValidateCheckpointResult } from '@aztec/stdlib/block';
|
|
18
18
|
import { PublishedCheckpoint } from '@aztec/stdlib/checkpoint';
|
|
19
|
-
import { type L1RollupConstants, getEpochAtSlot,
|
|
19
|
+
import { type L1RollupConstants, getEpochAtSlot, getSlotAtNextL1Block } from '@aztec/stdlib/epoch-helpers';
|
|
20
20
|
import { computeInHashFromL1ToL2Messages } from '@aztec/stdlib/messaging';
|
|
21
21
|
import { type Traceable, type Tracer, execInSpan, trackSpan } from '@aztec/telemetry-client';
|
|
22
22
|
|
|
@@ -28,6 +28,7 @@ import {
|
|
|
28
28
|
retrievedToPublishedCheckpoint,
|
|
29
29
|
} from '../l1/data_retrieval.js';
|
|
30
30
|
import type { KVArchiverDataStore } from '../store/kv_archiver_store.js';
|
|
31
|
+
import type { L2TipsCache } from '../store/l2_tips_cache.js';
|
|
31
32
|
import type { InboxMessage } from '../structs/inbox_message.js';
|
|
32
33
|
import { ArchiverDataStoreUpdater } from './data_store_updater.js';
|
|
33
34
|
import type { ArchiverInstrumentation } from './instrumentation.js';
|
|
@@ -77,9 +78,10 @@ export class ArchiverL1Synchronizer implements Traceable {
|
|
|
77
78
|
private readonly l1Constants: L1RollupConstants & { l1StartBlockHash: Buffer32; genesisArchiveRoot: Fr },
|
|
78
79
|
private readonly events: ArchiverEmitter,
|
|
79
80
|
tracer: Tracer,
|
|
81
|
+
l2TipsCache?: L2TipsCache,
|
|
80
82
|
private readonly log: Logger = createLogger('archiver:l1-sync'),
|
|
81
83
|
) {
|
|
82
|
-
this.updater = new ArchiverDataStoreUpdater(this.store);
|
|
84
|
+
this.updater = new ArchiverDataStoreUpdater(this.store, l2TipsCache);
|
|
83
85
|
this.tracer = tracer;
|
|
84
86
|
}
|
|
85
87
|
|
|
@@ -249,8 +251,7 @@ export class ArchiverL1Synchronizer implements Traceable {
|
|
|
249
251
|
const firstUncheckpointedBlockSlot = firstUncheckpointedBlockHeader?.getSlot();
|
|
250
252
|
|
|
251
253
|
// What's the slot at the next L1 block? All blocks for slots strictly before this one should've been checkpointed by now.
|
|
252
|
-
const
|
|
253
|
-
const slotAtNextL1Block = getSlotAtTimestamp(nextL1BlockTimestamp, this.l1Constants);
|
|
254
|
+
const slotAtNextL1Block = getSlotAtNextL1Block(currentL1Timestamp, this.l1Constants);
|
|
254
255
|
|
|
255
256
|
// Prune provisional blocks from slots that have ended without being checkpointed
|
|
256
257
|
if (firstUncheckpointedBlockSlot !== undefined && firstUncheckpointedBlockSlot < slotAtNextL1Block) {
|
|
@@ -551,7 +552,7 @@ export class ArchiverL1Synchronizer implements Traceable {
|
|
|
551
552
|
if (provenCheckpointNumber === 0) {
|
|
552
553
|
const localProvenCheckpointNumber = await this.store.getProvenCheckpointNumber();
|
|
553
554
|
if (localProvenCheckpointNumber !== provenCheckpointNumber) {
|
|
554
|
-
await this.
|
|
555
|
+
await this.updater.setProvenCheckpointNumber(provenCheckpointNumber);
|
|
555
556
|
this.log.info(`Rolled back proven chain to checkpoint ${provenCheckpointNumber}`, { provenCheckpointNumber });
|
|
556
557
|
}
|
|
557
558
|
}
|
|
@@ -583,13 +584,13 @@ export class ArchiverL1Synchronizer implements Traceable {
|
|
|
583
584
|
) {
|
|
584
585
|
const localProvenCheckpointNumber = await this.store.getProvenCheckpointNumber();
|
|
585
586
|
if (localProvenCheckpointNumber !== provenCheckpointNumber) {
|
|
586
|
-
await this.
|
|
587
|
+
await this.updater.setProvenCheckpointNumber(provenCheckpointNumber);
|
|
587
588
|
this.log.info(`Updated proven chain to checkpoint ${provenCheckpointNumber}`, { provenCheckpointNumber });
|
|
588
589
|
const provenSlotNumber = localCheckpointForDestinationProvenCheckpointNumber.header.slotNumber;
|
|
589
590
|
const provenEpochNumber: EpochNumber = getEpochAtSlot(provenSlotNumber, this.l1Constants);
|
|
590
591
|
const lastBlockNumberInCheckpoint =
|
|
591
592
|
localCheckpointForDestinationProvenCheckpointNumber.startBlock +
|
|
592
|
-
localCheckpointForDestinationProvenCheckpointNumber.
|
|
593
|
+
localCheckpointForDestinationProvenCheckpointNumber.blockCount -
|
|
593
594
|
1;
|
|
594
595
|
|
|
595
596
|
this.events.emit(L2BlockSourceEvents.L2BlockProven, {
|
|
@@ -598,7 +599,7 @@ export class ArchiverL1Synchronizer implements Traceable {
|
|
|
598
599
|
slotNumber: provenSlotNumber,
|
|
599
600
|
epochNumber: provenEpochNumber,
|
|
600
601
|
});
|
|
601
|
-
this.instrumentation.
|
|
602
|
+
this.instrumentation.updateLastProvenCheckpoint(localCheckpointForDestinationProvenCheckpointNumber);
|
|
602
603
|
} else {
|
|
603
604
|
this.log.trace(`Proven checkpoint ${provenCheckpointNumber} already stored.`);
|
|
604
605
|
}
|