@aztec/archiver 0.71.0 → 0.72.1
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 +4 -4
- package/dest/archiver/archiver.d.ts.map +1 -1
- package/dest/archiver/archiver.js +6 -6
- package/dest/archiver/archiver_store.d.ts +4 -4
- package/dest/archiver/archiver_store.d.ts.map +1 -1
- package/dest/archiver/archiver_store_test_suite.d.ts.map +1 -1
- package/dest/archiver/archiver_store_test_suite.js +97 -59
- package/dest/archiver/config.d.ts +1 -1
- package/dest/archiver/config.d.ts.map +1 -1
- package/dest/archiver/config.js +2 -2
- package/dest/archiver/data_retrieval.js +2 -2
- package/dest/archiver/kv_archiver_store/kv_archiver_store.d.ts +4 -4
- package/dest/archiver/kv_archiver_store/kv_archiver_store.d.ts.map +1 -1
- package/dest/archiver/kv_archiver_store/kv_archiver_store.js +4 -4
- package/dest/archiver/kv_archiver_store/log_store.d.ts +5 -5
- package/dest/archiver/kv_archiver_store/log_store.d.ts.map +1 -1
- package/dest/archiver/kv_archiver_store/log_store.js +83 -51
- package/dest/archiver/memory_archiver_store/memory_archiver_store.d.ts +7 -7
- package/dest/archiver/memory_archiver_store/memory_archiver_store.d.ts.map +1 -1
- package/dest/archiver/memory_archiver_store/memory_archiver_store.js +55 -56
- package/dest/factory.js +2 -2
- package/dest/rpc/index.d.ts +1 -1
- package/dest/rpc/index.d.ts.map +1 -1
- package/dest/rpc/index.js +5 -5
- 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 +2 -1
- package/dest/test/mock_l2_block_source.d.ts +1 -1
- package/dest/test/mock_l2_block_source.d.ts.map +1 -1
- package/dest/test/mock_l2_block_source.js +3 -3
- package/package.json +13 -13
- package/src/archiver/archiver.ts +9 -8
- package/src/archiver/archiver_store.ts +5 -4
- package/src/archiver/archiver_store_test_suite.ts +103 -70
- package/src/archiver/config.ts +2 -2
- package/src/archiver/data_retrieval.ts +1 -1
- package/src/archiver/kv_archiver_store/kv_archiver_store.ts +6 -5
- package/src/archiver/kv_archiver_store/log_store.ts +108 -61
- package/src/archiver/memory_archiver_store/memory_archiver_store.ts +62 -59
- package/src/factory.ts +1 -1
- package/src/rpc/index.ts +4 -4
- package/src/test/mock_archiver.ts +1 -0
- package/src/test/mock_l2_block_source.ts +2 -2
|
@@ -1,18 +1,23 @@
|
|
|
1
1
|
import {
|
|
2
2
|
ContractClass2BlockL2Logs,
|
|
3
|
+
ExtendedPublicLog,
|
|
3
4
|
ExtendedUnencryptedL2Log,
|
|
4
|
-
type
|
|
5
|
+
type GetContractClassLogsResponse,
|
|
6
|
+
type GetPublicLogsResponse,
|
|
5
7
|
type L2Block,
|
|
6
8
|
type LogFilter,
|
|
7
9
|
LogId,
|
|
8
10
|
TxScopedL2Log,
|
|
9
|
-
|
|
10
|
-
type UnencryptedL2Log,
|
|
11
|
+
UnencryptedL2Log,
|
|
11
12
|
} from '@aztec/circuit-types';
|
|
12
|
-
import { Fr, PrivateLog } from '@aztec/circuits.js';
|
|
13
|
-
import {
|
|
13
|
+
import { type Fr, PrivateLog, PublicLog } from '@aztec/circuits.js';
|
|
14
|
+
import {
|
|
15
|
+
INITIAL_L2_BLOCK_NUM,
|
|
16
|
+
MAX_NOTE_HASHES_PER_TX,
|
|
17
|
+
PUBLIC_LOG_DATA_SIZE_IN_FIELDS,
|
|
18
|
+
} from '@aztec/circuits.js/constants';
|
|
14
19
|
import { createLogger } from '@aztec/foundation/log';
|
|
15
|
-
import { BufferReader } from '@aztec/foundation/serialize';
|
|
20
|
+
import { BufferReader, numToUInt32BE } from '@aztec/foundation/serialize';
|
|
16
21
|
import { type AztecKVStore, type AztecMap } from '@aztec/kv-store';
|
|
17
22
|
|
|
18
23
|
import { type BlockStore } from './block_store.js';
|
|
@@ -24,7 +29,7 @@ export class LogStore {
|
|
|
24
29
|
#logsByTag: AztecMap<string, Buffer[]>;
|
|
25
30
|
#logTagsByBlock: AztecMap<number, string[]>;
|
|
26
31
|
#privateLogsByBlock: AztecMap<number, Buffer>;
|
|
27
|
-
#
|
|
32
|
+
#publicLogsByBlock: AztecMap<number, Buffer>;
|
|
28
33
|
#contractClassLogsByBlock: AztecMap<number, Buffer>;
|
|
29
34
|
#logsMaxPageSize: number;
|
|
30
35
|
#log = createLogger('archiver:log_store');
|
|
@@ -33,7 +38,7 @@ export class LogStore {
|
|
|
33
38
|
this.#logsByTag = db.openMap('archiver_tagged_logs_by_tag');
|
|
34
39
|
this.#logTagsByBlock = db.openMap('archiver_log_tags_by_block');
|
|
35
40
|
this.#privateLogsByBlock = db.openMap('archiver_private_logs_by_block');
|
|
36
|
-
this.#
|
|
41
|
+
this.#publicLogsByBlock = db.openMap('archiver_public_logs_by_block');
|
|
37
42
|
this.#contractClassLogsByBlock = db.openMap('archiver_contract_class_logs_by_block');
|
|
38
43
|
|
|
39
44
|
this.#logsMaxPageSize = logsMaxPageSize;
|
|
@@ -70,39 +75,48 @@ export class LogStore {
|
|
|
70
75
|
const dataStartIndexForBlock =
|
|
71
76
|
block.header.state.partial.noteHashTree.nextAvailableLeafIndex -
|
|
72
77
|
block.body.txEffects.length * MAX_NOTE_HASHES_PER_TX;
|
|
73
|
-
block.body.
|
|
74
|
-
const txHash =
|
|
78
|
+
block.body.txEffects.forEach((txEffect, txIndex) => {
|
|
79
|
+
const txHash = txEffect.txHash;
|
|
75
80
|
const dataStartIndexForTx = dataStartIndexForBlock + txIndex * MAX_NOTE_HASHES_PER_TX;
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
+
txEffect.publicLogs.forEach(log => {
|
|
82
|
+
// Check that each log stores 3 lengths in its first field. If not, it's not a tagged log:
|
|
83
|
+
const firstFieldBuf = log.log[0].toBuffer();
|
|
84
|
+
if (
|
|
85
|
+
!firstFieldBuf.subarray(0, 24).equals(Buffer.alloc(24)) ||
|
|
86
|
+
firstFieldBuf[26] !== 0 ||
|
|
87
|
+
firstFieldBuf[29] !== 0
|
|
88
|
+
) {
|
|
89
|
+
// See parseLogFromPublic - the first field of a tagged log is 8 bytes structured:
|
|
90
|
+
// [ publicLen[0], publicLen[1], 0, privateLen[0], privateLen[1], 0, ciphertextLen[0], ciphertextLen[1]]
|
|
91
|
+
this.#log.warn(`Skipping public log with invalid first field: ${log.log[0]}`);
|
|
81
92
|
return;
|
|
82
93
|
}
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
).toNumber();
|
|
93
|
-
correctedBuffer.writeUInt8(byte, i);
|
|
94
|
-
}
|
|
95
|
-
const tag = new Fr(correctedBuffer);
|
|
96
|
-
|
|
97
|
-
this.#log.debug(`Found tagged unencrypted log with tag ${tag.toString()} in block ${block.number}`);
|
|
98
|
-
const currentLogs = taggedLogs.get(tag.toString()) ?? [];
|
|
99
|
-
currentLogs.push(
|
|
100
|
-
new TxScopedL2Log(txHash, dataStartIndexForTx, block.number, /* isFromPublic */ true, log.data).toBuffer(),
|
|
101
|
-
);
|
|
102
|
-
taggedLogs.set(tag.toString(), currentLogs);
|
|
103
|
-
} catch (err) {
|
|
104
|
-
this.#log.warn(`Failed to add tagged log to store: ${err}`);
|
|
94
|
+
// Check that the length values line up with the log contents
|
|
95
|
+
const publicValuesLength = firstFieldBuf.subarray(-8).readUint16BE();
|
|
96
|
+
const privateValuesLength = firstFieldBuf.subarray(-8).readUint16BE(3);
|
|
97
|
+
// Add 1 for the first field holding lengths
|
|
98
|
+
const totalLogLength = 1 + publicValuesLength + privateValuesLength;
|
|
99
|
+
// Note that zeroes can be valid log values, so we can only assert that we do not go over the given length
|
|
100
|
+
if (totalLogLength > PUBLIC_LOG_DATA_SIZE_IN_FIELDS || log.log.slice(totalLogLength).find(f => !f.isZero())) {
|
|
101
|
+
this.#log.warn(`Skipping invalid tagged public log with first field: ${log.log[0]}`);
|
|
102
|
+
return;
|
|
105
103
|
}
|
|
104
|
+
|
|
105
|
+
// The first elt stores lengths as above => tag is in fields[1]
|
|
106
|
+
const tag = log.log[1];
|
|
107
|
+
|
|
108
|
+
this.#log.debug(`Found tagged public log with tag ${tag.toString()} in block ${block.number}`);
|
|
109
|
+
const currentLogs = taggedLogs.get(tag.toString()) ?? [];
|
|
110
|
+
currentLogs.push(
|
|
111
|
+
new TxScopedL2Log(
|
|
112
|
+
txHash,
|
|
113
|
+
dataStartIndexForTx,
|
|
114
|
+
block.number,
|
|
115
|
+
/* isFromPublic */ true,
|
|
116
|
+
log.toBuffer(),
|
|
117
|
+
).toBuffer(),
|
|
118
|
+
);
|
|
119
|
+
taggedLogs.set(tag.toString(), currentLogs);
|
|
106
120
|
});
|
|
107
121
|
});
|
|
108
122
|
return taggedLogs;
|
|
@@ -150,7 +164,17 @@ export class LogStore {
|
|
|
150
164
|
.map(log => log.toBuffer());
|
|
151
165
|
void this.#privateLogsByBlock.set(block.number, Buffer.concat(privateLogsInBlock));
|
|
152
166
|
|
|
153
|
-
|
|
167
|
+
const publicLogsInBlock = block.body.txEffects
|
|
168
|
+
.map((txEffect, txIndex) =>
|
|
169
|
+
[
|
|
170
|
+
numToUInt32BE(txIndex),
|
|
171
|
+
numToUInt32BE(txEffect.publicLogs.length),
|
|
172
|
+
txEffect.publicLogs.map(log => log.toBuffer()),
|
|
173
|
+
].flat(),
|
|
174
|
+
)
|
|
175
|
+
.flat();
|
|
176
|
+
|
|
177
|
+
void this.#publicLogsByBlock.set(block.number, Buffer.concat(publicLogsInBlock));
|
|
154
178
|
void this.#contractClassLogsByBlock.set(block.number, block.body.contractClassLogs.toBuffer());
|
|
155
179
|
});
|
|
156
180
|
|
|
@@ -165,7 +189,7 @@ export class LogStore {
|
|
|
165
189
|
return this.db.transaction(() => {
|
|
166
190
|
blocks.forEach(block => {
|
|
167
191
|
void this.#privateLogsByBlock.delete(block.number);
|
|
168
|
-
void this.#
|
|
192
|
+
void this.#publicLogsByBlock.delete(block.number);
|
|
169
193
|
void this.#logTagsByBlock.delete(block.number);
|
|
170
194
|
});
|
|
171
195
|
|
|
@@ -209,21 +233,21 @@ export class LogStore {
|
|
|
209
233
|
}
|
|
210
234
|
|
|
211
235
|
/**
|
|
212
|
-
* Gets
|
|
236
|
+
* Gets public logs based on the provided filter.
|
|
213
237
|
* @param filter - The filter to apply to the logs.
|
|
214
238
|
* @returns The requested logs.
|
|
215
239
|
*/
|
|
216
|
-
|
|
240
|
+
getPublicLogs(filter: LogFilter): GetPublicLogsResponse {
|
|
217
241
|
if (filter.afterLog) {
|
|
218
|
-
return this.#
|
|
242
|
+
return this.#filterPublicLogsBetweenBlocks(filter);
|
|
219
243
|
} else if (filter.txHash) {
|
|
220
|
-
return this.#
|
|
244
|
+
return this.#filterPublicLogsOfTx(filter);
|
|
221
245
|
} else {
|
|
222
|
-
return this.#
|
|
246
|
+
return this.#filterPublicLogsBetweenBlocks(filter);
|
|
223
247
|
}
|
|
224
248
|
}
|
|
225
249
|
|
|
226
|
-
#
|
|
250
|
+
#filterPublicLogsOfTx(filter: LogFilter): GetPublicLogsResponse {
|
|
227
251
|
if (!filter.txHash) {
|
|
228
252
|
throw new Error('Missing txHash');
|
|
229
253
|
}
|
|
@@ -233,18 +257,27 @@ export class LogStore {
|
|
|
233
257
|
return { logs: [], maxLogsHit: false };
|
|
234
258
|
}
|
|
235
259
|
|
|
236
|
-
const buffer = this.#
|
|
237
|
-
const
|
|
260
|
+
const buffer = this.#publicLogsByBlock.get(blockNumber) ?? Buffer.alloc(0);
|
|
261
|
+
const publicLogsInBlock: [PublicLog[]] = [[]];
|
|
262
|
+
const reader = new BufferReader(buffer);
|
|
263
|
+
while (reader.remainingBytes() > 0) {
|
|
264
|
+
const indexOfTx = reader.readNumber();
|
|
265
|
+
const numLogsInTx = reader.readNumber();
|
|
266
|
+
publicLogsInBlock[indexOfTx] = [];
|
|
267
|
+
for (let i = 0; i < numLogsInTx; i++) {
|
|
268
|
+
publicLogsInBlock[indexOfTx].push(reader.readObject(PublicLog));
|
|
269
|
+
}
|
|
270
|
+
}
|
|
238
271
|
|
|
239
|
-
const txLogs =
|
|
272
|
+
const txLogs = publicLogsInBlock[txIndex];
|
|
240
273
|
|
|
241
|
-
const logs:
|
|
274
|
+
const logs: ExtendedPublicLog[] = [];
|
|
242
275
|
const maxLogsHit = this.#accumulateLogs(logs, blockNumber, txIndex, txLogs, filter);
|
|
243
276
|
|
|
244
277
|
return { logs, maxLogsHit };
|
|
245
278
|
}
|
|
246
279
|
|
|
247
|
-
#
|
|
280
|
+
#filterPublicLogsBetweenBlocks(filter: LogFilter): GetPublicLogsResponse {
|
|
248
281
|
const start =
|
|
249
282
|
filter.afterLog?.blockNumber ?? Math.max(filter.fromBlock ?? INITIAL_L2_BLOCK_NUM, INITIAL_L2_BLOCK_NUM);
|
|
250
283
|
const end = filter.toBlock;
|
|
@@ -256,13 +289,22 @@ export class LogStore {
|
|
|
256
289
|
};
|
|
257
290
|
}
|
|
258
291
|
|
|
259
|
-
const logs:
|
|
292
|
+
const logs: ExtendedPublicLog[] = [];
|
|
260
293
|
|
|
261
294
|
let maxLogsHit = false;
|
|
262
|
-
loopOverBlocks: for (const [blockNumber, logBuffer] of this.#
|
|
263
|
-
const
|
|
264
|
-
|
|
265
|
-
|
|
295
|
+
loopOverBlocks: for (const [blockNumber, logBuffer] of this.#publicLogsByBlock.entries({ start, end })) {
|
|
296
|
+
const publicLogsInBlock: [PublicLog[]] = [[]];
|
|
297
|
+
const reader = new BufferReader(logBuffer);
|
|
298
|
+
while (reader.remainingBytes() > 0) {
|
|
299
|
+
const indexOfTx = reader.readNumber();
|
|
300
|
+
const numLogsInTx = reader.readNumber();
|
|
301
|
+
publicLogsInBlock[indexOfTx] = [];
|
|
302
|
+
for (let i = 0; i < numLogsInTx; i++) {
|
|
303
|
+
publicLogsInBlock[indexOfTx].push(reader.readObject(PublicLog));
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
for (let txIndex = filter.afterLog?.txIndex ?? 0; txIndex < publicLogsInBlock.length; txIndex++) {
|
|
307
|
+
const txLogs = publicLogsInBlock[txIndex];
|
|
266
308
|
maxLogsHit = this.#accumulateLogs(logs, blockNumber, txIndex, txLogs, filter);
|
|
267
309
|
if (maxLogsHit) {
|
|
268
310
|
this.#log.debug(`Max logs hit at block ${blockNumber}`);
|
|
@@ -279,7 +321,7 @@ export class LogStore {
|
|
|
279
321
|
* @param filter - The filter to apply to the logs.
|
|
280
322
|
* @returns The requested logs.
|
|
281
323
|
*/
|
|
282
|
-
getContractClassLogs(filter: LogFilter):
|
|
324
|
+
getContractClassLogs(filter: LogFilter): GetContractClassLogsResponse {
|
|
283
325
|
if (filter.afterLog) {
|
|
284
326
|
return this.#filterContractClassLogsBetweenBlocks(filter);
|
|
285
327
|
} else if (filter.txHash) {
|
|
@@ -289,7 +331,7 @@ export class LogStore {
|
|
|
289
331
|
}
|
|
290
332
|
}
|
|
291
333
|
|
|
292
|
-
#filterContractClassLogsOfTx(filter: LogFilter):
|
|
334
|
+
#filterContractClassLogsOfTx(filter: LogFilter): GetContractClassLogsResponse {
|
|
293
335
|
if (!filter.txHash) {
|
|
294
336
|
throw new Error('Missing txHash');
|
|
295
337
|
}
|
|
@@ -310,7 +352,7 @@ export class LogStore {
|
|
|
310
352
|
return { logs, maxLogsHit };
|
|
311
353
|
}
|
|
312
354
|
|
|
313
|
-
#filterContractClassLogsBetweenBlocks(filter: LogFilter):
|
|
355
|
+
#filterContractClassLogsBetweenBlocks(filter: LogFilter): GetContractClassLogsResponse {
|
|
314
356
|
const start =
|
|
315
357
|
filter.afterLog?.blockNumber ?? Math.max(filter.fromBlock ?? INITIAL_L2_BLOCK_NUM, INITIAL_L2_BLOCK_NUM);
|
|
316
358
|
const end = filter.toBlock;
|
|
@@ -341,10 +383,10 @@ export class LogStore {
|
|
|
341
383
|
}
|
|
342
384
|
|
|
343
385
|
#accumulateLogs(
|
|
344
|
-
results: ExtendedUnencryptedL2Log[],
|
|
386
|
+
results: (ExtendedUnencryptedL2Log | ExtendedPublicLog)[],
|
|
345
387
|
blockNumber: number,
|
|
346
388
|
txIndex: number,
|
|
347
|
-
txLogs: UnencryptedL2Log[],
|
|
389
|
+
txLogs: (UnencryptedL2Log | PublicLog)[],
|
|
348
390
|
filter: LogFilter,
|
|
349
391
|
): boolean {
|
|
350
392
|
let maxLogsHit = false;
|
|
@@ -352,7 +394,12 @@ export class LogStore {
|
|
|
352
394
|
for (; logIndex < txLogs.length; logIndex++) {
|
|
353
395
|
const log = txLogs[logIndex];
|
|
354
396
|
if (!filter.contractAddress || log.contractAddress.equals(filter.contractAddress)) {
|
|
355
|
-
|
|
397
|
+
if (log instanceof UnencryptedL2Log) {
|
|
398
|
+
results.push(new ExtendedUnencryptedL2Log(new LogId(blockNumber, txIndex, logIndex), log));
|
|
399
|
+
} else {
|
|
400
|
+
results.push(new ExtendedPublicLog(new LogId(blockNumber, txIndex, logIndex), log));
|
|
401
|
+
}
|
|
402
|
+
|
|
356
403
|
if (results.length >= this.#logsMaxPageSize) {
|
|
357
404
|
maxLogsHit = true;
|
|
358
405
|
break;
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
type ContractClass2BlockL2Logs,
|
|
3
|
+
ExtendedPublicLog,
|
|
3
4
|
ExtendedUnencryptedL2Log,
|
|
4
|
-
type
|
|
5
|
+
type GetContractClassLogsResponse,
|
|
6
|
+
type GetPublicLogsResponse,
|
|
5
7
|
type InBlock,
|
|
6
8
|
type InboxLeaf,
|
|
7
9
|
type L2Block,
|
|
@@ -12,7 +14,6 @@ import {
|
|
|
12
14
|
type TxHash,
|
|
13
15
|
TxReceipt,
|
|
14
16
|
TxScopedL2Log,
|
|
15
|
-
type UnencryptedL2BlockL2Logs,
|
|
16
17
|
wrapInBlock,
|
|
17
18
|
} from '@aztec/circuit-types';
|
|
18
19
|
import {
|
|
@@ -25,7 +26,9 @@ import {
|
|
|
25
26
|
INITIAL_L2_BLOCK_NUM,
|
|
26
27
|
MAX_NOTE_HASHES_PER_TX,
|
|
27
28
|
MAX_NULLIFIERS_PER_TX,
|
|
29
|
+
PUBLIC_LOG_DATA_SIZE_IN_FIELDS,
|
|
28
30
|
type PrivateLog,
|
|
31
|
+
type PublicLog,
|
|
29
32
|
type UnconstrainedFunctionWithMembershipProof,
|
|
30
33
|
} from '@aztec/circuits.js';
|
|
31
34
|
import { FunctionSelector } from '@aztec/foundation/abi';
|
|
@@ -57,7 +60,7 @@ export class MemoryArchiverStore implements ArchiverDataStore {
|
|
|
57
60
|
|
|
58
61
|
private privateLogsPerBlock: Map<number, PrivateLog[]> = new Map();
|
|
59
62
|
|
|
60
|
-
private
|
|
63
|
+
private publicLogsPerBlock: Map<number, PublicLog[]> = new Map();
|
|
61
64
|
|
|
62
65
|
private contractClassLogsPerBlock: Map<number, ContractClass2BlockL2Logs> = new Map();
|
|
63
66
|
|
|
@@ -89,7 +92,7 @@ export class MemoryArchiverStore implements ArchiverDataStore {
|
|
|
89
92
|
#log = createLogger('archiver:data-store');
|
|
90
93
|
|
|
91
94
|
constructor(
|
|
92
|
-
/** The max number of logs that can be obtained in 1 "
|
|
95
|
+
/** The max number of logs that can be obtained in 1 "getPublicLogs" call. */
|
|
93
96
|
public readonly maxLogs: number,
|
|
94
97
|
) {}
|
|
95
98
|
|
|
@@ -249,43 +252,43 @@ export class MemoryArchiverStore implements ArchiverDataStore {
|
|
|
249
252
|
const dataStartIndexForBlock =
|
|
250
253
|
block.header.state.partial.noteHashTree.nextAvailableLeafIndex -
|
|
251
254
|
block.body.txEffects.length * MAX_NOTE_HASHES_PER_TX;
|
|
252
|
-
block.body.
|
|
253
|
-
const txHash =
|
|
255
|
+
block.body.txEffects.forEach((txEffect, txIndex) => {
|
|
256
|
+
const txHash = txEffect.txHash;
|
|
254
257
|
const dataStartIndexForTx = dataStartIndexForBlock + txIndex * MAX_NOTE_HASHES_PER_TX;
|
|
255
|
-
|
|
256
|
-
|
|
258
|
+
txEffect.publicLogs.forEach(log => {
|
|
259
|
+
// Check that each log stores 3 lengths in its first field. If not, it's not a tagged log:
|
|
260
|
+
const firstFieldBuf = log.log[0].toBuffer();
|
|
257
261
|
if (
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
262
|
+
!firstFieldBuf.subarray(0, 24).equals(Buffer.alloc(24)) ||
|
|
263
|
+
firstFieldBuf[26] !== 0 ||
|
|
264
|
+
firstFieldBuf[29] !== 0
|
|
261
265
|
) {
|
|
262
|
-
|
|
266
|
+
// See parseLogFromPublic - the first field of a tagged log is 8 bytes structured:
|
|
267
|
+
// [ publicLen[0], publicLen[1], 0, privateLen[0], privateLen[1], 0, ciphertextLen[0], ciphertextLen[1]]
|
|
268
|
+
this.#log.warn(`Skipping public log with invalid first field: ${log.log[0]}`);
|
|
263
269
|
return;
|
|
264
270
|
}
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
).toNumber();
|
|
275
|
-
correctedBuffer.writeUInt8(byte, i);
|
|
276
|
-
}
|
|
277
|
-
const tag = new Fr(correctedBuffer);
|
|
278
|
-
this.#log.verbose(`Storing unencrypted tagged log with tag ${tag.toString()} in block ${block.number}`);
|
|
279
|
-
const currentLogs = this.taggedLogs.get(tag.toString()) || [];
|
|
280
|
-
this.taggedLogs.set(tag.toString(), [
|
|
281
|
-
...currentLogs,
|
|
282
|
-
new TxScopedL2Log(txHash, dataStartIndexForTx, block.number, /* isFromPublic */ true, log.data),
|
|
283
|
-
]);
|
|
284
|
-
const currentTagsInBlock = this.logTagsPerBlock.get(block.number) || [];
|
|
285
|
-
this.logTagsPerBlock.set(block.number, [...currentTagsInBlock, tag]);
|
|
286
|
-
} catch (err) {
|
|
287
|
-
this.#log.warn(`Failed to add tagged log to store: ${err}`);
|
|
271
|
+
// Check that the length values line up with the log contents
|
|
272
|
+
const publicValuesLength = firstFieldBuf.subarray(-8).readUint16BE();
|
|
273
|
+
const privateValuesLength = firstFieldBuf.subarray(-8).readUint16BE(3);
|
|
274
|
+
// Add 1 for the first field holding lengths
|
|
275
|
+
const totalLogLength = 1 + publicValuesLength + privateValuesLength;
|
|
276
|
+
// Note that zeroes can be valid log values, so we can only assert that we do not go over the given length
|
|
277
|
+
if (totalLogLength > PUBLIC_LOG_DATA_SIZE_IN_FIELDS || log.log.slice(totalLogLength).find(f => !f.isZero())) {
|
|
278
|
+
this.#log.warn(`Skipping invalid tagged public log with first field: ${log.log[0]}`);
|
|
279
|
+
return;
|
|
288
280
|
}
|
|
281
|
+
|
|
282
|
+
// The first elt stores lengths => tag is in fields[1]
|
|
283
|
+
const tag = log.log[1];
|
|
284
|
+
this.#log.verbose(`Storing public tagged log with tag ${tag.toString()} in block ${block.number}`);
|
|
285
|
+
const currentLogs = this.taggedLogs.get(tag.toString()) || [];
|
|
286
|
+
this.taggedLogs.set(tag.toString(), [
|
|
287
|
+
...currentLogs,
|
|
288
|
+
new TxScopedL2Log(txHash, dataStartIndexForTx, block.number, /* isFromPublic */ true, log.toBuffer()),
|
|
289
|
+
]);
|
|
290
|
+
const currentTagsInBlock = this.logTagsPerBlock.get(block.number) || [];
|
|
291
|
+
this.logTagsPerBlock.set(block.number, [...currentTagsInBlock, tag]);
|
|
289
292
|
});
|
|
290
293
|
});
|
|
291
294
|
}
|
|
@@ -300,7 +303,7 @@ export class MemoryArchiverStore implements ArchiverDataStore {
|
|
|
300
303
|
void this.#storeTaggedLogsFromPrivate(block);
|
|
301
304
|
void this.#storeTaggedLogsFromPublic(block);
|
|
302
305
|
this.privateLogsPerBlock.set(block.number, block.body.txEffects.map(txEffect => txEffect.privateLogs).flat());
|
|
303
|
-
this.
|
|
306
|
+
this.publicLogsPerBlock.set(block.number, block.body.txEffects.map(txEffect => txEffect.publicLogs).flat());
|
|
304
307
|
this.contractClassLogsPerBlock.set(block.number, block.body.contractClassLogs);
|
|
305
308
|
});
|
|
306
309
|
return Promise.resolve(true);
|
|
@@ -316,7 +319,7 @@ export class MemoryArchiverStore implements ArchiverDataStore {
|
|
|
316
319
|
|
|
317
320
|
blocks.forEach(block => {
|
|
318
321
|
this.privateLogsPerBlock.delete(block.number);
|
|
319
|
-
this.
|
|
322
|
+
this.publicLogsPerBlock.delete(block.number);
|
|
320
323
|
this.logTagsPerBlock.delete(block.number);
|
|
321
324
|
this.contractClassLogsPerBlock.delete(block.number);
|
|
322
325
|
});
|
|
@@ -518,12 +521,12 @@ export class MemoryArchiverStore implements ArchiverDataStore {
|
|
|
518
521
|
}
|
|
519
522
|
|
|
520
523
|
/**
|
|
521
|
-
* Gets
|
|
524
|
+
* Gets public logs based on the provided filter.
|
|
522
525
|
* @param filter - The filter to apply to the logs.
|
|
523
526
|
* @returns The requested logs.
|
|
524
527
|
* @remarks Works by doing an intersection of all params in the filter.
|
|
525
528
|
*/
|
|
526
|
-
|
|
529
|
+
getPublicLogs(filter: LogFilter): Promise<GetPublicLogsResponse> {
|
|
527
530
|
let txHash: TxHash | undefined;
|
|
528
531
|
let fromBlock = 0;
|
|
529
532
|
let toBlock = this.l2Blocks.length + INITIAL_L2_BLOCK_NUM;
|
|
@@ -564,34 +567,34 @@ export class MemoryArchiverStore implements ArchiverDataStore {
|
|
|
564
567
|
|
|
565
568
|
const contractAddress = filter.contractAddress;
|
|
566
569
|
|
|
567
|
-
const logs:
|
|
570
|
+
const logs: ExtendedPublicLog[] = [];
|
|
568
571
|
|
|
569
572
|
for (; fromBlock < toBlock; fromBlock++) {
|
|
570
573
|
const block = this.l2Blocks[fromBlock - INITIAL_L2_BLOCK_NUM];
|
|
571
|
-
const blockLogs = this.
|
|
574
|
+
const blockLogs = this.publicLogsPerBlock.get(fromBlock);
|
|
572
575
|
|
|
573
576
|
if (blockLogs) {
|
|
574
|
-
for (;
|
|
575
|
-
const
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
)
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
577
|
+
for (let logIndex = 0; logIndex < blockLogs.length; logIndex++) {
|
|
578
|
+
const log = blockLogs[logIndex];
|
|
579
|
+
const thisTxEffect = block.data.body.txEffects.filter(effect => effect.publicLogs.includes(log))[0];
|
|
580
|
+
const thisTxIndexInBlock = block.data.body.txEffects.indexOf(thisTxEffect);
|
|
581
|
+
const thisLogIndexInTx = thisTxEffect.publicLogs.indexOf(log);
|
|
582
|
+
if (
|
|
583
|
+
(!txHash || thisTxEffect.txHash.equals(txHash)) &&
|
|
584
|
+
(!contractAddress || log.contractAddress.equals(contractAddress)) &&
|
|
585
|
+
thisTxIndexInBlock >= txIndexInBlock &&
|
|
586
|
+
thisLogIndexInTx >= logIndexInTx
|
|
587
|
+
) {
|
|
588
|
+
logs.push(new ExtendedPublicLog(new LogId(block.data.number, thisTxIndexInBlock, thisLogIndexInTx), log));
|
|
589
|
+
if (logs.length === this.maxLogs) {
|
|
590
|
+
return Promise.resolve({
|
|
591
|
+
logs,
|
|
592
|
+
maxLogsHit: true,
|
|
593
|
+
});
|
|
589
594
|
}
|
|
590
595
|
}
|
|
591
|
-
logIndexInTx = 0;
|
|
592
596
|
}
|
|
593
597
|
}
|
|
594
|
-
txIndexInBlock = 0;
|
|
595
598
|
}
|
|
596
599
|
|
|
597
600
|
return Promise.resolve({
|
|
@@ -607,7 +610,7 @@ export class MemoryArchiverStore implements ArchiverDataStore {
|
|
|
607
610
|
* @returns The requested logs.
|
|
608
611
|
* @remarks Works by doing an intersection of all params in the filter.
|
|
609
612
|
*/
|
|
610
|
-
getContractClassLogs(filter: LogFilter): Promise<
|
|
613
|
+
getContractClassLogs(filter: LogFilter): Promise<GetContractClassLogsResponse> {
|
|
611
614
|
let txHash: TxHash | undefined;
|
|
612
615
|
let fromBlock = 0;
|
|
613
616
|
let toBlock = this.l2Blocks.length + INITIAL_L2_BLOCK_NUM;
|
package/src/factory.ts
CHANGED
|
@@ -41,7 +41,7 @@ export async function createArchiver(
|
|
|
41
41
|
async function registerProtocolContracts(store: KVArchiverDataStore) {
|
|
42
42
|
const blockNumber = 0;
|
|
43
43
|
for (const name of protocolContractNames) {
|
|
44
|
-
const contract = getCanonicalProtocolContract(name);
|
|
44
|
+
const contract = await getCanonicalProtocolContract(name);
|
|
45
45
|
const contractClassPublic: ContractClassPublic = {
|
|
46
46
|
...contract.contractClass,
|
|
47
47
|
privateFunctions: [],
|
package/src/rpc/index.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { type ArchiverApi, ArchiverApiSchema } from '@aztec/circuit-types';
|
|
2
|
-
import { createSafeJsonRpcClient
|
|
3
|
-
import {
|
|
2
|
+
import { createSafeJsonRpcClient } from '@aztec/foundation/json-rpc/client';
|
|
3
|
+
import { createTracedJsonRpcServer, makeTracedFetch } from '@aztec/telemetry-client';
|
|
4
4
|
|
|
5
|
-
export function createArchiverClient(url: string, fetch =
|
|
5
|
+
export function createArchiverClient(url: string, fetch = makeTracedFetch([1, 2, 3], true)): ArchiverApi {
|
|
6
6
|
return createSafeJsonRpcClient<ArchiverApi>(url, ArchiverApiSchema, false, 'archiver', fetch);
|
|
7
7
|
}
|
|
8
8
|
|
|
9
9
|
export function createArchiverRpcServer(handler: ArchiverApi) {
|
|
10
|
-
return
|
|
10
|
+
return createTracedJsonRpcServer(handler, ArchiverApiSchema);
|
|
11
11
|
}
|
|
@@ -24,10 +24,10 @@ export class MockL2BlockSource implements L2BlockSource {
|
|
|
24
24
|
|
|
25
25
|
private log = createLogger('archiver:mock_l2_block_source');
|
|
26
26
|
|
|
27
|
-
public createBlocks(numBlocks: number) {
|
|
27
|
+
public async createBlocks(numBlocks: number) {
|
|
28
28
|
for (let i = 0; i < numBlocks; i++) {
|
|
29
29
|
const blockNum = this.l2Blocks.length + 1;
|
|
30
|
-
const block = L2Block.random(blockNum);
|
|
30
|
+
const block = await L2Block.random(blockNum);
|
|
31
31
|
this.l2Blocks.push(block);
|
|
32
32
|
}
|
|
33
33
|
|