@aztec/archiver 3.0.0-nightly.20251223 → 3.0.0-nightly.20251225
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 +6 -10
- package/dest/archiver/archiver.d.ts.map +1 -1
- package/dest/archiver/archiver.js +10 -9
- package/dest/archiver/archiver_store.d.ts +11 -8
- package/dest/archiver/archiver_store.d.ts.map +1 -1
- package/dest/archiver/archiver_store_test_suite.d.ts +1 -1
- package/dest/archiver/archiver_store_test_suite.d.ts.map +1 -1
- package/dest/archiver/archiver_store_test_suite.js +134 -39
- package/dest/archiver/kv_archiver_store/kv_archiver_store.d.ts +4 -10
- package/dest/archiver/kv_archiver_store/kv_archiver_store.d.ts.map +1 -1
- package/dest/archiver/kv_archiver_store/kv_archiver_store.js +9 -8
- package/dest/archiver/kv_archiver_store/log_store.d.ts +11 -8
- package/dest/archiver/kv_archiver_store/log_store.d.ts.map +1 -1
- package/dest/archiver/kv_archiver_store/log_store.js +112 -46
- package/dest/archiver/l1/data_retrieval.js +2 -2
- package/dest/test/mock_l2_block_source.d.ts +8 -2
- package/dest/test/mock_l2_block_source.d.ts.map +1 -1
- package/dest/test/mock_l2_block_source.js +8 -0
- package/package.json +13 -13
- package/src/archiver/archiver.ts +20 -11
- package/src/archiver/archiver_store.ts +11 -7
- package/src/archiver/archiver_store_test_suite.ts +157 -43
- package/src/archiver/kv_archiver_store/kv_archiver_store.ts +11 -10
- package/src/archiver/kv_archiver_store/log_store.ts +140 -51
- package/src/archiver/l1/data_retrieval.ts +2 -2
- package/src/test/mock_l2_block_source.ts +11 -0
|
@@ -4,6 +4,7 @@ import { Fr } from '@aztec/foundation/curves/bn254';
|
|
|
4
4
|
import { createLogger } from '@aztec/foundation/log';
|
|
5
5
|
import { BufferReader, numToUInt32BE } from '@aztec/foundation/serialize';
|
|
6
6
|
import type { AztecAsyncKVStore, AztecAsyncMap } from '@aztec/kv-store';
|
|
7
|
+
import type { AztecAddress } from '@aztec/stdlib/aztec-address';
|
|
7
8
|
import { L2BlockHash, L2BlockNew } from '@aztec/stdlib/block';
|
|
8
9
|
import type { GetContractClassLogsResponse, GetPublicLogsResponse } from '@aztec/stdlib/interfaces/client';
|
|
9
10
|
import {
|
|
@@ -13,6 +14,8 @@ import {
|
|
|
13
14
|
type LogFilter,
|
|
14
15
|
LogId,
|
|
15
16
|
PublicLog,
|
|
17
|
+
type SiloedTag,
|
|
18
|
+
Tag,
|
|
16
19
|
TxScopedL2Log,
|
|
17
20
|
} from '@aztec/stdlib/logs';
|
|
18
21
|
|
|
@@ -22,8 +25,12 @@ import type { BlockStore } from './block_store.js';
|
|
|
22
25
|
* A store for logs
|
|
23
26
|
*/
|
|
24
27
|
export class LogStore {
|
|
25
|
-
|
|
26
|
-
#
|
|
28
|
+
// `tag` --> private logs
|
|
29
|
+
#privateLogsByTag: AztecAsyncMap<string, Buffer[]>;
|
|
30
|
+
// `{contractAddress}_${tag}` --> public logs
|
|
31
|
+
#publicLogsByContractAndTag: AztecAsyncMap<string, Buffer[]>;
|
|
32
|
+
#privateLogKeysByBlock: AztecAsyncMap<number, string[]>;
|
|
33
|
+
#publicLogKeysByBlock: AztecAsyncMap<number, string[]>;
|
|
27
34
|
#publicLogsByBlock: AztecAsyncMap<number, Buffer>;
|
|
28
35
|
#contractClassLogsByBlock: AztecAsyncMap<number, Buffer>;
|
|
29
36
|
#logsMaxPageSize: number;
|
|
@@ -34,29 +41,42 @@ export class LogStore {
|
|
|
34
41
|
private blockStore: BlockStore,
|
|
35
42
|
logsMaxPageSize: number = 1000,
|
|
36
43
|
) {
|
|
37
|
-
this.#
|
|
38
|
-
this.#
|
|
44
|
+
this.#privateLogsByTag = db.openMap('archiver_private_tagged_logs_by_tag');
|
|
45
|
+
this.#publicLogsByContractAndTag = db.openMap('archiver_public_tagged_logs_by_tag');
|
|
46
|
+
this.#privateLogKeysByBlock = db.openMap('archiver_private_log_keys_by_block');
|
|
47
|
+
this.#publicLogKeysByBlock = db.openMap('archiver_public_log_keys_by_block');
|
|
39
48
|
this.#publicLogsByBlock = db.openMap('archiver_public_logs_by_block');
|
|
40
49
|
this.#contractClassLogsByBlock = db.openMap('archiver_contract_class_logs_by_block');
|
|
41
50
|
|
|
42
51
|
this.#logsMaxPageSize = logsMaxPageSize;
|
|
43
52
|
}
|
|
44
53
|
|
|
45
|
-
|
|
54
|
+
/**
|
|
55
|
+
* Extracts tagged logs from a single block, grouping them into private and public maps.
|
|
56
|
+
*
|
|
57
|
+
* @param block - The L2 block to extract logs from.
|
|
58
|
+
* @returns An object containing the private and public tagged logs for the block.
|
|
59
|
+
*/
|
|
60
|
+
async #extractTaggedLogsFromBlock(block: L2BlockNew) {
|
|
46
61
|
const blockHash = L2BlockHash.fromField(await block.hash());
|
|
47
|
-
|
|
62
|
+
// SiloedTag (as string) -> array of log buffers.
|
|
63
|
+
const privateTaggedLogs = new Map<string, Buffer[]>();
|
|
64
|
+
// "{contractAddress}_{tag}" (as string) -> array of log buffers.
|
|
65
|
+
const publicTaggedLogs = new Map<string, Buffer[]>();
|
|
48
66
|
const dataStartIndexForBlock =
|
|
49
67
|
block.header.state.partial.noteHashTree.nextAvailableLeafIndex -
|
|
50
68
|
block.body.txEffects.length * MAX_NOTE_HASHES_PER_TX;
|
|
69
|
+
|
|
51
70
|
block.body.txEffects.forEach((txEffect, txIndex) => {
|
|
52
71
|
const txHash = txEffect.txHash;
|
|
53
72
|
const dataStartIndexForTx = dataStartIndexForBlock + txIndex * MAX_NOTE_HASHES_PER_TX;
|
|
54
73
|
|
|
55
74
|
txEffect.privateLogs.forEach((log, logIndex) => {
|
|
75
|
+
// Private logs use SiloedTag (already siloed by kernel)
|
|
56
76
|
const tag = log.fields[0];
|
|
57
77
|
this.#log.debug(`Found private log with tag ${tag.toString()} in block ${block.number}`);
|
|
58
78
|
|
|
59
|
-
const currentLogs =
|
|
79
|
+
const currentLogs = privateTaggedLogs.get(tag.toString()) ?? [];
|
|
60
80
|
currentLogs.push(
|
|
61
81
|
new TxScopedL2Log(
|
|
62
82
|
txHash,
|
|
@@ -68,14 +88,19 @@ export class LogStore {
|
|
|
68
88
|
log,
|
|
69
89
|
).toBuffer(),
|
|
70
90
|
);
|
|
71
|
-
|
|
91
|
+
privateTaggedLogs.set(tag.toString(), currentLogs);
|
|
72
92
|
});
|
|
73
93
|
|
|
74
94
|
txEffect.publicLogs.forEach((log, logIndex) => {
|
|
95
|
+
// Public logs use Tag directly (not siloed) and are stored with contract address
|
|
75
96
|
const tag = log.fields[0];
|
|
76
|
-
|
|
97
|
+
const contractAddress = log.contractAddress;
|
|
98
|
+
const key = `${contractAddress.toString()}_${tag.toString()}`;
|
|
99
|
+
this.#log.debug(
|
|
100
|
+
`Found public log with tag ${tag.toString()} from contract ${contractAddress.toString()} in block ${block.number}`,
|
|
101
|
+
);
|
|
77
102
|
|
|
78
|
-
const currentLogs =
|
|
103
|
+
const currentLogs = publicTaggedLogs.get(key) ?? [];
|
|
79
104
|
currentLogs.push(
|
|
80
105
|
new TxScopedL2Log(
|
|
81
106
|
txHash,
|
|
@@ -87,49 +112,102 @@ export class LogStore {
|
|
|
87
112
|
log,
|
|
88
113
|
).toBuffer(),
|
|
89
114
|
);
|
|
90
|
-
|
|
115
|
+
publicTaggedLogs.set(key, currentLogs);
|
|
91
116
|
});
|
|
92
117
|
});
|
|
93
|
-
|
|
118
|
+
|
|
119
|
+
return { privateTaggedLogs, publicTaggedLogs };
|
|
94
120
|
}
|
|
95
121
|
|
|
96
122
|
/**
|
|
97
|
-
*
|
|
98
|
-
* @param blocks - The blocks
|
|
99
|
-
* @returns
|
|
123
|
+
* Extracts and aggregates tagged logs from a list of blocks.
|
|
124
|
+
* @param blocks - The blocks to extract logs from.
|
|
125
|
+
* @returns A map from tag (as string) to an array of serialized private logs belonging to that tag, and a map from
|
|
126
|
+
* "{contractAddress}_{tag}" (as string) to an array of serialized public logs belonging to that key.
|
|
100
127
|
*/
|
|
101
|
-
async
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
128
|
+
async #extractTaggedLogs(
|
|
129
|
+
blocks: L2BlockNew[],
|
|
130
|
+
): Promise<{ privateTaggedLogs: Map<string, Buffer[]>; publicTaggedLogs: Map<string, Buffer[]> }> {
|
|
131
|
+
const taggedLogsInBlocks = await Promise.all(blocks.map(block => this.#extractTaggedLogsFromBlock(block)));
|
|
132
|
+
|
|
133
|
+
// Now we merge the maps from each block into a single map.
|
|
134
|
+
const privateTaggedLogs = taggedLogsInBlocks.reduce((acc, { privateTaggedLogs }) => {
|
|
135
|
+
for (const [tag, logs] of privateTaggedLogs.entries()) {
|
|
105
136
|
const currentLogs = acc.get(tag) ?? [];
|
|
106
137
|
acc.set(tag, currentLogs.concat(logs));
|
|
107
138
|
}
|
|
108
139
|
return acc;
|
|
109
140
|
}, new Map<string, Buffer[]>());
|
|
110
|
-
|
|
141
|
+
|
|
142
|
+
const publicTaggedLogs = taggedLogsInBlocks.reduce((acc, { publicTaggedLogs }) => {
|
|
143
|
+
for (const [key, logs] of publicTaggedLogs.entries()) {
|
|
144
|
+
const currentLogs = acc.get(key) ?? [];
|
|
145
|
+
acc.set(key, currentLogs.concat(logs));
|
|
146
|
+
}
|
|
147
|
+
return acc;
|
|
148
|
+
}, new Map<string, Buffer[]>());
|
|
149
|
+
|
|
150
|
+
return { privateTaggedLogs, publicTaggedLogs };
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Append new logs to the store's list.
|
|
155
|
+
* @param blocks - The blocks for which to add the logs.
|
|
156
|
+
* @returns True if the operation is successful.
|
|
157
|
+
*/
|
|
158
|
+
async addLogs(blocks: L2BlockNew[]): Promise<boolean> {
|
|
159
|
+
const { privateTaggedLogs, publicTaggedLogs } = await this.#extractTaggedLogs(blocks);
|
|
160
|
+
|
|
161
|
+
const keysOfPrivateLogsToUpdate = Array.from(privateTaggedLogs.keys());
|
|
162
|
+
const keysOfPublicLogsToUpdate = Array.from(publicTaggedLogs.keys());
|
|
111
163
|
|
|
112
164
|
return this.db.transactionAsync(async () => {
|
|
113
|
-
const
|
|
114
|
-
|
|
165
|
+
const currentPrivateTaggedLogs = await Promise.all(
|
|
166
|
+
keysOfPrivateLogsToUpdate.map(async key => ({
|
|
167
|
+
tag: key,
|
|
168
|
+
logBuffers: await this.#privateLogsByTag.getAsync(key),
|
|
169
|
+
})),
|
|
115
170
|
);
|
|
116
|
-
|
|
171
|
+
currentPrivateTaggedLogs.forEach(taggedLogBuffer => {
|
|
117
172
|
if (taggedLogBuffer.logBuffers && taggedLogBuffer.logBuffers.length > 0) {
|
|
118
|
-
|
|
173
|
+
privateTaggedLogs.set(
|
|
119
174
|
taggedLogBuffer.tag,
|
|
120
|
-
taggedLogBuffer.logBuffers!.concat(
|
|
175
|
+
taggedLogBuffer.logBuffers!.concat(privateTaggedLogs.get(taggedLogBuffer.tag)!),
|
|
176
|
+
);
|
|
177
|
+
}
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
const currentPublicTaggedLogs = await Promise.all(
|
|
181
|
+
keysOfPublicLogsToUpdate.map(async key => ({
|
|
182
|
+
key,
|
|
183
|
+
logBuffers: await this.#publicLogsByContractAndTag.getAsync(key),
|
|
184
|
+
})),
|
|
185
|
+
);
|
|
186
|
+
currentPublicTaggedLogs.forEach(taggedLogBuffer => {
|
|
187
|
+
if (taggedLogBuffer.logBuffers && taggedLogBuffer.logBuffers.length > 0) {
|
|
188
|
+
publicTaggedLogs.set(
|
|
189
|
+
taggedLogBuffer.key,
|
|
190
|
+
taggedLogBuffer.logBuffers!.concat(publicTaggedLogs.get(taggedLogBuffer.key)!),
|
|
121
191
|
);
|
|
122
192
|
}
|
|
123
193
|
});
|
|
194
|
+
|
|
124
195
|
for (const block of blocks) {
|
|
125
196
|
const blockHash = await block.hash();
|
|
126
197
|
|
|
127
|
-
const
|
|
128
|
-
for (const [tag, logs] of
|
|
129
|
-
await this.#
|
|
130
|
-
|
|
198
|
+
const privateTagsInBlock: string[] = [];
|
|
199
|
+
for (const [tag, logs] of privateTaggedLogs.entries()) {
|
|
200
|
+
await this.#privateLogsByTag.set(tag, logs);
|
|
201
|
+
privateTagsInBlock.push(tag);
|
|
131
202
|
}
|
|
132
|
-
await this.#
|
|
203
|
+
await this.#privateLogKeysByBlock.set(block.number, privateTagsInBlock);
|
|
204
|
+
|
|
205
|
+
const publicKeysInBlock: string[] = [];
|
|
206
|
+
for (const [key, logs] of publicTaggedLogs.entries()) {
|
|
207
|
+
await this.#publicLogsByContractAndTag.set(key, logs);
|
|
208
|
+
publicKeysInBlock.push(key);
|
|
209
|
+
}
|
|
210
|
+
await this.#publicLogKeysByBlock.set(block.number, publicKeysInBlock);
|
|
133
211
|
|
|
134
212
|
const publicLogsInBlock = block.body.txEffects
|
|
135
213
|
.map((txEffect, txIndex) =>
|
|
@@ -178,44 +256,55 @@ export class LogStore {
|
|
|
178
256
|
|
|
179
257
|
deleteLogs(blocks: L2BlockNew[]): Promise<boolean> {
|
|
180
258
|
return this.db.transactionAsync(async () => {
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
259
|
+
await Promise.all(
|
|
260
|
+
blocks.map(async block => {
|
|
261
|
+
// Delete private logs
|
|
262
|
+
const privateKeys = (await this.#privateLogKeysByBlock.getAsync(block.number)) ?? [];
|
|
263
|
+
await Promise.all(privateKeys.map(tag => this.#privateLogsByTag.delete(tag)));
|
|
264
|
+
|
|
265
|
+
// Delete public logs
|
|
266
|
+
const publicKeys = (await this.#publicLogKeysByBlock.getAsync(block.number)) ?? [];
|
|
267
|
+
await Promise.all(publicKeys.map(key => this.#publicLogsByContractAndTag.delete(key)));
|
|
268
|
+
}),
|
|
269
|
+
);
|
|
189
270
|
|
|
190
271
|
await Promise.all(
|
|
191
272
|
blocks.map(block =>
|
|
192
273
|
Promise.all([
|
|
193
274
|
this.#publicLogsByBlock.delete(block.number),
|
|
194
|
-
this.#
|
|
275
|
+
this.#privateLogKeysByBlock.delete(block.number),
|
|
276
|
+
this.#publicLogKeysByBlock.delete(block.number),
|
|
195
277
|
this.#contractClassLogsByBlock.delete(block.number),
|
|
196
278
|
]),
|
|
197
279
|
),
|
|
198
280
|
);
|
|
199
281
|
|
|
200
|
-
await Promise.all(tagsToDelete.map(tag => this.#logsByTag.delete(tag.toString())));
|
|
201
282
|
return true;
|
|
202
283
|
});
|
|
203
284
|
}
|
|
204
285
|
|
|
205
286
|
/**
|
|
206
|
-
* Gets all logs that match any of the
|
|
207
|
-
*
|
|
208
|
-
* @returns For each received tag, an array of matching logs is returned. An empty array implies no logs match
|
|
209
|
-
* that tag.
|
|
287
|
+
* Gets all private logs that match any of the `tags`. For each tag, an array of matching logs is returned. An empty
|
|
288
|
+
* array implies no logs match that tag.
|
|
210
289
|
*/
|
|
211
|
-
async
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
290
|
+
async getPrivateLogsByTags(tags: SiloedTag[]): Promise<TxScopedL2Log[][]> {
|
|
291
|
+
const logs = await Promise.all(tags.map(tag => this.#privateLogsByTag.getAsync(tag.toString())));
|
|
292
|
+
|
|
293
|
+
return logs.map(logBuffers => logBuffers?.map(logBuffer => TxScopedL2Log.fromBuffer(logBuffer)) ?? []);
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
/**
|
|
297
|
+
* Gets all public logs that match any of the `tags` from the specified contract. For each tag, an array of matching
|
|
298
|
+
* logs is returned. An empty array implies no logs match that tag.
|
|
299
|
+
*/
|
|
300
|
+
async getPublicLogsByTagsFromContract(contractAddress: AztecAddress, tags: Tag[]): Promise<TxScopedL2Log[][]> {
|
|
301
|
+
const logs = await Promise.all(
|
|
302
|
+
tags.map(tag => {
|
|
303
|
+
const key = `${contractAddress.toString()}_${tag.value.toString()}`;
|
|
304
|
+
return this.#publicLogsByContractAndTag.getAsync(key);
|
|
305
|
+
}),
|
|
218
306
|
);
|
|
307
|
+
return logs.map(logBuffers => logBuffers?.map(logBuffer => TxScopedL2Log.fromBuffer(logBuffer)) ?? []);
|
|
219
308
|
}
|
|
220
309
|
|
|
221
310
|
/**
|
|
@@ -331,7 +331,7 @@ export async function getCheckpointBlobDataFromBlobs(
|
|
|
331
331
|
logger: Logger,
|
|
332
332
|
isHistoricalSync: boolean,
|
|
333
333
|
): Promise<CheckpointBlobData> {
|
|
334
|
-
const blobBodies = await blobClient.getBlobSidecar(blockHash, blobHashes,
|
|
334
|
+
const blobBodies = await blobClient.getBlobSidecar(blockHash, blobHashes, { isHistoricalSync });
|
|
335
335
|
if (blobBodies.length === 0) {
|
|
336
336
|
throw new NoBlobBodiesFoundError(checkpointNumber);
|
|
337
337
|
}
|
|
@@ -339,7 +339,7 @@ export async function getCheckpointBlobDataFromBlobs(
|
|
|
339
339
|
let checkpointBlobData: CheckpointBlobData;
|
|
340
340
|
try {
|
|
341
341
|
// Attempt to decode the checkpoint blob data.
|
|
342
|
-
checkpointBlobData = decodeCheckpointBlobDataFromBlobs(blobBodies
|
|
342
|
+
checkpointBlobData = decodeCheckpointBlobDataFromBlobs(blobBodies);
|
|
343
343
|
} catch (err: any) {
|
|
344
344
|
if (err instanceof BlobDeserializationError) {
|
|
345
345
|
logger.fatal(err.message);
|
|
@@ -10,6 +10,7 @@ import type { AztecAddress } from '@aztec/stdlib/aztec-address';
|
|
|
10
10
|
import {
|
|
11
11
|
L2Block,
|
|
12
12
|
L2BlockHash,
|
|
13
|
+
L2BlockNew,
|
|
13
14
|
type L2BlockSource,
|
|
14
15
|
type L2Tips,
|
|
15
16
|
PublishedL2Block,
|
|
@@ -105,6 +106,16 @@ export class MockL2BlockSource implements L2BlockSource, ContractDataSource {
|
|
|
105
106
|
return Promise.resolve(this.l2Blocks[number - 1]);
|
|
106
107
|
}
|
|
107
108
|
|
|
109
|
+
/**
|
|
110
|
+
* Gets an L2 block (new format).
|
|
111
|
+
* @param number - The block number to return.
|
|
112
|
+
* @returns The requested L2 block.
|
|
113
|
+
*/
|
|
114
|
+
public getL2BlockNew(number: BlockNumber): Promise<L2BlockNew | undefined> {
|
|
115
|
+
const block = this.l2Blocks[number - 1];
|
|
116
|
+
return Promise.resolve(block?.toL2Block());
|
|
117
|
+
}
|
|
118
|
+
|
|
108
119
|
/**
|
|
109
120
|
* Gets up to `limit` amount of L2 blocks starting from `from`.
|
|
110
121
|
* @param from - Number of the first block to return (inclusive).
|