@aztec/archiver 0.65.2 → 0.66.0
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 +18 -22
- package/dest/archiver/archiver.d.ts.map +1 -1
- package/dest/archiver/archiver.js +143 -99
- package/dest/archiver/archiver_store.d.ts +7 -8
- 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 +126 -150
- package/dest/archiver/config.d.ts +6 -12
- package/dest/archiver/config.d.ts.map +1 -1
- package/dest/archiver/config.js +6 -1
- package/dest/archiver/data_retrieval.d.ts +2 -3
- package/dest/archiver/data_retrieval.d.ts.map +1 -1
- package/dest/archiver/data_retrieval.js +14 -15
- package/dest/archiver/instrumentation.d.ts +2 -7
- package/dest/archiver/instrumentation.d.ts.map +1 -1
- package/dest/archiver/instrumentation.js +3 -6
- package/dest/archiver/kv_archiver_store/kv_archiver_store.d.ts +7 -8
- package/dest/archiver/kv_archiver_store/kv_archiver_store.d.ts.map +1 -1
- package/dest/archiver/kv_archiver_store/kv_archiver_store.js +7 -8
- package/dest/archiver/kv_archiver_store/log_store.d.ts +7 -8
- package/dest/archiver/kv_archiver_store/log_store.d.ts.map +1 -1
- package/dest/archiver/kv_archiver_store/log_store.js +55 -95
- package/dest/archiver/memory_archiver_store/memory_archiver_store.d.ts +8 -10
- package/dest/archiver/memory_archiver_store/memory_archiver_store.d.ts.map +1 -1
- package/dest/archiver/memory_archiver_store/memory_archiver_store.js +50 -57
- package/dest/index.d.ts +2 -2
- package/dest/index.d.ts.map +1 -1
- package/dest/index.js +3 -42
- package/dest/test/mock_l2_block_source.d.ts.map +1 -1
- package/dest/test/mock_l2_block_source.js +2 -2
- package/package.json +11 -13
- package/src/archiver/archiver.ts +199 -191
- package/src/archiver/archiver_store.ts +6 -13
- package/src/archiver/archiver_store_test_suite.ts +160 -186
- package/src/archiver/config.ts +12 -12
- package/src/archiver/data_retrieval.ts +12 -17
- package/src/archiver/instrumentation.ts +3 -5
- package/src/archiver/kv_archiver_store/kv_archiver_store.ts +7 -14
- package/src/archiver/kv_archiver_store/log_store.ts +68 -118
- package/src/archiver/memory_archiver_store/memory_archiver_store.ts +51 -65
- package/src/index.ts +5 -59
- package/src/test/mock_l2_block_source.ts +1 -2
- package/dest/archiver/epoch_helpers.d.ts +0 -20
- package/dest/archiver/epoch_helpers.d.ts.map +0 -1
- package/dest/archiver/epoch_helpers.js +0 -34
- package/src/archiver/epoch_helpers.ts +0 -54
|
@@ -1,12 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
|
-
type FromLogType,
|
|
3
2
|
type GetUnencryptedLogsResponse,
|
|
4
3
|
type InBlock,
|
|
5
4
|
type InboxLeaf,
|
|
6
5
|
type L2Block,
|
|
7
|
-
type L2BlockL2Logs,
|
|
8
6
|
type LogFilter,
|
|
9
|
-
type LogType,
|
|
10
7
|
type TxHash,
|
|
11
8
|
type TxReceipt,
|
|
12
9
|
type TxScopedL2Log,
|
|
@@ -17,6 +14,7 @@ import {
|
|
|
17
14
|
type ExecutablePrivateFunctionWithMembershipProof,
|
|
18
15
|
type Fr,
|
|
19
16
|
type Header,
|
|
17
|
+
type PrivateLog,
|
|
20
18
|
type UnconstrainedFunctionWithMembershipProof,
|
|
21
19
|
} from '@aztec/circuits.js';
|
|
22
20
|
import { type ContractArtifact, FunctionSelector } from '@aztec/foundation/abi';
|
|
@@ -266,19 +264,14 @@ export class KVArchiverDataStore implements ArchiverDataStore {
|
|
|
266
264
|
}
|
|
267
265
|
|
|
268
266
|
/**
|
|
269
|
-
*
|
|
270
|
-
* @param
|
|
271
|
-
* @param limit - The number of
|
|
272
|
-
* @
|
|
273
|
-
* @returns The requested logs.
|
|
267
|
+
* Retrieves all private logs from up to `limit` blocks, starting from the block number `from`.
|
|
268
|
+
* @param from - The block number from which to begin retrieving logs.
|
|
269
|
+
* @param limit - The maximum number of blocks to retrieve logs from.
|
|
270
|
+
* @returns An array of private logs from the specified range of blocks.
|
|
274
271
|
*/
|
|
275
|
-
|
|
276
|
-
start: number,
|
|
277
|
-
limit: number,
|
|
278
|
-
logType: TLogType,
|
|
279
|
-
): Promise<L2BlockL2Logs<FromLogType<TLogType>>[]> {
|
|
272
|
+
getPrivateLogs(from: number, limit: number): Promise<PrivateLog[]> {
|
|
280
273
|
try {
|
|
281
|
-
return Promise.resolve(Array.from(this.#logStore.
|
|
274
|
+
return Promise.resolve(Array.from(this.#logStore.getPrivateLogs(from, limit)));
|
|
282
275
|
} catch (err) {
|
|
283
276
|
return Promise.reject(err);
|
|
284
277
|
}
|
|
@@ -1,23 +1,18 @@
|
|
|
1
1
|
import {
|
|
2
|
-
type Body,
|
|
3
2
|
ContractClass2BlockL2Logs,
|
|
4
|
-
EncryptedL2BlockL2Logs,
|
|
5
|
-
EncryptedNoteL2BlockL2Logs,
|
|
6
3
|
ExtendedUnencryptedL2Log,
|
|
7
|
-
type FromLogType,
|
|
8
4
|
type GetUnencryptedLogsResponse,
|
|
9
5
|
type L2Block,
|
|
10
|
-
type L2BlockL2Logs,
|
|
11
6
|
type LogFilter,
|
|
12
7
|
LogId,
|
|
13
|
-
LogType,
|
|
14
8
|
TxScopedL2Log,
|
|
15
9
|
UnencryptedL2BlockL2Logs,
|
|
16
10
|
type UnencryptedL2Log,
|
|
17
11
|
} from '@aztec/circuit-types';
|
|
18
|
-
import { Fr } from '@aztec/circuits.js';
|
|
12
|
+
import { Fr, PrivateLog } from '@aztec/circuits.js';
|
|
19
13
|
import { INITIAL_L2_BLOCK_NUM, MAX_NOTE_HASHES_PER_TX } from '@aztec/circuits.js/constants';
|
|
20
14
|
import { createDebugLogger } from '@aztec/foundation/log';
|
|
15
|
+
import { BufferReader } from '@aztec/foundation/serialize';
|
|
21
16
|
import { type AztecKVStore, type AztecMap } from '@aztec/kv-store';
|
|
22
17
|
|
|
23
18
|
import { type BlockStore } from './block_store.js';
|
|
@@ -26,72 +21,83 @@ import { type BlockStore } from './block_store.js';
|
|
|
26
21
|
* A store for logs
|
|
27
22
|
*/
|
|
28
23
|
export class LogStore {
|
|
29
|
-
#noteEncryptedLogsByBlock: AztecMap<number, Buffer>;
|
|
30
24
|
#logsByTag: AztecMap<string, Buffer[]>;
|
|
31
25
|
#logTagsByBlock: AztecMap<number, string[]>;
|
|
32
|
-
#
|
|
26
|
+
#privateLogsByBlock: AztecMap<number, Buffer>;
|
|
33
27
|
#unencryptedLogsByBlock: AztecMap<number, Buffer>;
|
|
34
28
|
#contractClassLogsByBlock: AztecMap<number, Buffer>;
|
|
35
29
|
#logsMaxPageSize: number;
|
|
36
30
|
#log = createDebugLogger('aztec:archiver:log_store');
|
|
37
31
|
|
|
38
32
|
constructor(private db: AztecKVStore, private blockStore: BlockStore, logsMaxPageSize: number = 1000) {
|
|
39
|
-
this.#noteEncryptedLogsByBlock = db.openMap('archiver_note_encrypted_logs_by_block');
|
|
40
33
|
this.#logsByTag = db.openMap('archiver_tagged_logs_by_tag');
|
|
41
34
|
this.#logTagsByBlock = db.openMap('archiver_log_tags_by_block');
|
|
42
|
-
this.#
|
|
35
|
+
this.#privateLogsByBlock = db.openMap('archiver_private_logs_by_block');
|
|
43
36
|
this.#unencryptedLogsByBlock = db.openMap('archiver_unencrypted_logs_by_block');
|
|
44
37
|
this.#contractClassLogsByBlock = db.openMap('archiver_contract_class_logs_by_block');
|
|
45
38
|
|
|
46
39
|
this.#logsMaxPageSize = logsMaxPageSize;
|
|
47
40
|
}
|
|
48
41
|
|
|
49
|
-
#
|
|
42
|
+
#extractTaggedLogsFromPrivate(block: L2Block) {
|
|
50
43
|
const taggedLogs = new Map<string, Buffer[]>();
|
|
51
44
|
const dataStartIndexForBlock =
|
|
52
45
|
block.header.state.partial.noteHashTree.nextAvailableLeafIndex -
|
|
53
46
|
block.body.numberOfTxsIncludingPadded * MAX_NOTE_HASHES_PER_TX;
|
|
54
|
-
block.body
|
|
47
|
+
block.body.txEffects.forEach((txEffect, txIndex) => {
|
|
48
|
+
const txHash = txEffect.txHash;
|
|
49
|
+
const dataStartIndexForTx = dataStartIndexForBlock + txIndex * MAX_NOTE_HASHES_PER_TX;
|
|
50
|
+
txEffect.privateLogs.forEach(log => {
|
|
51
|
+
const tag = log.fields[0];
|
|
52
|
+
const currentLogs = taggedLogs.get(tag.toString()) ?? [];
|
|
53
|
+
currentLogs.push(
|
|
54
|
+
new TxScopedL2Log(
|
|
55
|
+
txHash,
|
|
56
|
+
dataStartIndexForTx,
|
|
57
|
+
block.number,
|
|
58
|
+
/* isFromPublic */ false,
|
|
59
|
+
log.toBuffer(),
|
|
60
|
+
).toBuffer(),
|
|
61
|
+
);
|
|
62
|
+
taggedLogs.set(tag.toString(), currentLogs);
|
|
63
|
+
});
|
|
64
|
+
});
|
|
65
|
+
return taggedLogs;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
#extractTaggedLogsFromPublic(block: L2Block) {
|
|
69
|
+
const taggedLogs = new Map<string, Buffer[]>();
|
|
70
|
+
const dataStartIndexForBlock =
|
|
71
|
+
block.header.state.partial.noteHashTree.nextAvailableLeafIndex -
|
|
72
|
+
block.body.numberOfTxsIncludingPadded * MAX_NOTE_HASHES_PER_TX;
|
|
73
|
+
block.body.unencryptedLogs.txLogs.forEach((txLogs, txIndex) => {
|
|
55
74
|
const txHash = block.body.txEffects[txIndex].txHash;
|
|
56
75
|
const dataStartIndexForTx = dataStartIndexForBlock + txIndex * MAX_NOTE_HASHES_PER_TX;
|
|
57
76
|
const logs = txLogs.unrollLogs();
|
|
58
77
|
logs.forEach(log => {
|
|
59
|
-
if (
|
|
60
|
-
(logType == 'noteEncryptedLogs' && log.data.length < 32) ||
|
|
78
|
+
if (log.data.length < 32 * 33) {
|
|
61
79
|
// TODO remove when #9835 and #9836 are fixed
|
|
62
|
-
(
|
|
63
|
-
) {
|
|
64
|
-
this.#log.warn(`Skipping log (${logType}) with invalid data length: ${log.data.length}`);
|
|
80
|
+
this.#log.warn(`Skipping unencrypted log with insufficient data length: ${log.data.length}`);
|
|
65
81
|
return;
|
|
66
82
|
}
|
|
67
83
|
try {
|
|
68
|
-
let tag = Fr.ZERO;
|
|
69
84
|
// TODO remove when #9835 and #9836 are fixed. The partial note logs are emitted as bytes, but encoded as Fields.
|
|
70
85
|
// This means that for every 32 bytes of payload, we only have 1 byte of data.
|
|
71
86
|
// Also, the tag is not stored in the first 32 bytes of the log, (that's the length of public fields now) but in the next 32.
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
correctedBuffer.writeUInt8(byte, i);
|
|
80
|
-
}
|
|
81
|
-
tag = new Fr(correctedBuffer);
|
|
82
|
-
} else {
|
|
83
|
-
tag = new Fr(log.data.subarray(0, 32));
|
|
87
|
+
const correctedBuffer = Buffer.alloc(32);
|
|
88
|
+
const initialOffset = 32;
|
|
89
|
+
for (let i = 0; i < 32; i++) {
|
|
90
|
+
const byte = Fr.fromBuffer(
|
|
91
|
+
log.data.subarray(i * 32 + initialOffset, i * 32 + 32 + initialOffset),
|
|
92
|
+
).toNumber();
|
|
93
|
+
correctedBuffer.writeUInt8(byte, i);
|
|
84
94
|
}
|
|
85
|
-
|
|
95
|
+
const tag = new Fr(correctedBuffer);
|
|
96
|
+
|
|
97
|
+
this.#log.debug(`Found tagged unencrypted log with tag ${tag.toString()} in block ${block.number}`);
|
|
86
98
|
const currentLogs = taggedLogs.get(tag.toString()) ?? [];
|
|
87
99
|
currentLogs.push(
|
|
88
|
-
new TxScopedL2Log(
|
|
89
|
-
txHash,
|
|
90
|
-
dataStartIndexForTx,
|
|
91
|
-
block.number,
|
|
92
|
-
logType === 'unencryptedLogs',
|
|
93
|
-
log.data,
|
|
94
|
-
).toBuffer(),
|
|
100
|
+
new TxScopedL2Log(txHash, dataStartIndexForTx, block.number, /* isFromPublic */ true, log.data).toBuffer(),
|
|
95
101
|
);
|
|
96
102
|
taggedLogs.set(tag.toString(), currentLogs);
|
|
97
103
|
} catch (err) {
|
|
@@ -109,10 +115,7 @@ export class LogStore {
|
|
|
109
115
|
*/
|
|
110
116
|
async addLogs(blocks: L2Block[]): Promise<boolean> {
|
|
111
117
|
const taggedLogsToAdd = blocks
|
|
112
|
-
.flatMap(block => [
|
|
113
|
-
this.#extractTaggedLogs(block, 'noteEncryptedLogs'),
|
|
114
|
-
this.#extractTaggedLogs(block, 'unencryptedLogs'),
|
|
115
|
-
])
|
|
118
|
+
.flatMap(block => [this.#extractTaggedLogsFromPrivate(block), this.#extractTaggedLogsFromPublic(block)])
|
|
116
119
|
.reduce((acc, val) => {
|
|
117
120
|
for (const [tag, logs] of val.entries()) {
|
|
118
121
|
const currentLogs = acc.get(tag) ?? [];
|
|
@@ -140,8 +143,13 @@ export class LogStore {
|
|
|
140
143
|
tagsInBlock.push(tag);
|
|
141
144
|
}
|
|
142
145
|
void this.#logTagsByBlock.set(block.number, tagsInBlock);
|
|
143
|
-
|
|
144
|
-
|
|
146
|
+
|
|
147
|
+
const privateLogsInBlock = block.body.txEffects
|
|
148
|
+
.map(txEffect => txEffect.privateLogs)
|
|
149
|
+
.flat()
|
|
150
|
+
.map(log => log.toBuffer());
|
|
151
|
+
void this.#privateLogsByBlock.set(block.number, Buffer.concat(privateLogsInBlock));
|
|
152
|
+
|
|
145
153
|
void this.#unencryptedLogsByBlock.set(block.number, block.body.unencryptedLogs.toBuffer());
|
|
146
154
|
void this.#contractClassLogsByBlock.set(block.number, block.body.contractClassLogs.toBuffer());
|
|
147
155
|
});
|
|
@@ -156,8 +164,7 @@ export class LogStore {
|
|
|
156
164
|
});
|
|
157
165
|
return this.db.transaction(() => {
|
|
158
166
|
blocks.forEach(block => {
|
|
159
|
-
void this.#
|
|
160
|
-
void this.#encryptedLogsByBlock.delete(block.number);
|
|
167
|
+
void this.#privateLogsByBlock.delete(block.number);
|
|
161
168
|
void this.#unencryptedLogsByBlock.delete(block.number);
|
|
162
169
|
void this.#logTagsByBlock.delete(block.number);
|
|
163
170
|
});
|
|
@@ -171,43 +178,20 @@ export class LogStore {
|
|
|
171
178
|
}
|
|
172
179
|
|
|
173
180
|
/**
|
|
174
|
-
*
|
|
175
|
-
* @param start -
|
|
176
|
-
* @param limit - The number of
|
|
177
|
-
* @
|
|
178
|
-
* @returns The requested logs.
|
|
181
|
+
* Retrieves all private logs from up to `limit` blocks, starting from the block number `start`.
|
|
182
|
+
* @param start - The block number from which to begin retrieving logs.
|
|
183
|
+
* @param limit - The maximum number of blocks to retrieve logs from.
|
|
184
|
+
* @returns An array of private logs from the specified range of blocks.
|
|
179
185
|
*/
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
limit
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
switch (logType) {
|
|
187
|
-
case LogType.ENCRYPTED:
|
|
188
|
-
return this.#encryptedLogsByBlock;
|
|
189
|
-
case LogType.NOTEENCRYPTED:
|
|
190
|
-
return this.#noteEncryptedLogsByBlock;
|
|
191
|
-
case LogType.UNENCRYPTED:
|
|
192
|
-
default:
|
|
193
|
-
return this.#unencryptedLogsByBlock;
|
|
194
|
-
}
|
|
195
|
-
})();
|
|
196
|
-
const logTypeMap = (() => {
|
|
197
|
-
switch (logType) {
|
|
198
|
-
case LogType.ENCRYPTED:
|
|
199
|
-
return EncryptedL2BlockL2Logs;
|
|
200
|
-
case LogType.NOTEENCRYPTED:
|
|
201
|
-
return EncryptedNoteL2BlockL2Logs;
|
|
202
|
-
case LogType.UNENCRYPTED:
|
|
203
|
-
default:
|
|
204
|
-
return UnencryptedL2BlockL2Logs;
|
|
186
|
+
getPrivateLogs(start: number, limit: number) {
|
|
187
|
+
const logs = [];
|
|
188
|
+
for (const buffer of this.#privateLogsByBlock.values({ start, limit })) {
|
|
189
|
+
const reader = new BufferReader(buffer);
|
|
190
|
+
while (reader.remainingBytes() > 0) {
|
|
191
|
+
logs.push(reader.readObject(PrivateLog));
|
|
205
192
|
}
|
|
206
|
-
})();
|
|
207
|
-
const L2BlockL2Logs = logTypeMap;
|
|
208
|
-
for (const buffer of logMap.values({ start, limit })) {
|
|
209
|
-
yield L2BlockL2Logs.fromBuffer(buffer) as L2BlockL2Logs<FromLogType<TLogType>>;
|
|
210
193
|
}
|
|
194
|
+
return logs;
|
|
211
195
|
}
|
|
212
196
|
|
|
213
197
|
/**
|
|
@@ -249,7 +233,9 @@ export class LogStore {
|
|
|
249
233
|
return { logs: [], maxLogsHit: false };
|
|
250
234
|
}
|
|
251
235
|
|
|
252
|
-
const
|
|
236
|
+
const buffer = this.#unencryptedLogsByBlock.get(blockNumber) ?? Buffer.alloc(0);
|
|
237
|
+
const unencryptedLogsInBlock = UnencryptedL2BlockL2Logs.fromBuffer(buffer);
|
|
238
|
+
|
|
253
239
|
const txLogs = unencryptedLogsInBlock.txLogs[txIndex].unrollLogs();
|
|
254
240
|
|
|
255
241
|
const logs: ExtendedUnencryptedL2Log[] = [];
|
|
@@ -376,40 +362,4 @@ export class LogStore {
|
|
|
376
362
|
|
|
377
363
|
return maxLogsHit;
|
|
378
364
|
}
|
|
379
|
-
|
|
380
|
-
#getBlockLogs<TLogType extends LogType>(
|
|
381
|
-
blockNumber: number,
|
|
382
|
-
logType: TLogType,
|
|
383
|
-
): L2BlockL2Logs<FromLogType<TLogType>> {
|
|
384
|
-
const logMap = (() => {
|
|
385
|
-
switch (logType) {
|
|
386
|
-
case LogType.ENCRYPTED:
|
|
387
|
-
return this.#encryptedLogsByBlock;
|
|
388
|
-
case LogType.NOTEENCRYPTED:
|
|
389
|
-
return this.#noteEncryptedLogsByBlock;
|
|
390
|
-
case LogType.UNENCRYPTED:
|
|
391
|
-
default:
|
|
392
|
-
return this.#unencryptedLogsByBlock;
|
|
393
|
-
}
|
|
394
|
-
})();
|
|
395
|
-
const logTypeMap = (() => {
|
|
396
|
-
switch (logType) {
|
|
397
|
-
case LogType.ENCRYPTED:
|
|
398
|
-
return EncryptedL2BlockL2Logs;
|
|
399
|
-
case LogType.NOTEENCRYPTED:
|
|
400
|
-
return EncryptedNoteL2BlockL2Logs;
|
|
401
|
-
case LogType.UNENCRYPTED:
|
|
402
|
-
default:
|
|
403
|
-
return UnencryptedL2BlockL2Logs;
|
|
404
|
-
}
|
|
405
|
-
})();
|
|
406
|
-
const L2BlockL2Logs = logTypeMap;
|
|
407
|
-
const buffer = logMap.get(blockNumber);
|
|
408
|
-
|
|
409
|
-
if (!buffer) {
|
|
410
|
-
return new L2BlockL2Logs([]) as L2BlockL2Logs<FromLogType<TLogType>>;
|
|
411
|
-
}
|
|
412
|
-
|
|
413
|
-
return L2BlockL2Logs.fromBuffer(buffer) as L2BlockL2Logs<FromLogType<TLogType>>;
|
|
414
|
-
}
|
|
415
365
|
}
|
|
@@ -1,19 +1,13 @@
|
|
|
1
1
|
import {
|
|
2
|
-
type Body,
|
|
3
2
|
type ContractClass2BlockL2Logs,
|
|
4
|
-
type EncryptedL2BlockL2Logs,
|
|
5
|
-
type EncryptedNoteL2BlockL2Logs,
|
|
6
3
|
ExtendedUnencryptedL2Log,
|
|
7
|
-
type FromLogType,
|
|
8
4
|
type GetUnencryptedLogsResponse,
|
|
9
5
|
type InBlock,
|
|
10
6
|
type InboxLeaf,
|
|
11
7
|
type L2Block,
|
|
12
8
|
L2BlockHash,
|
|
13
|
-
type L2BlockL2Logs,
|
|
14
9
|
type LogFilter,
|
|
15
10
|
LogId,
|
|
16
|
-
LogType,
|
|
17
11
|
type TxEffect,
|
|
18
12
|
type TxHash,
|
|
19
13
|
TxReceipt,
|
|
@@ -31,6 +25,7 @@ import {
|
|
|
31
25
|
INITIAL_L2_BLOCK_NUM,
|
|
32
26
|
MAX_NOTE_HASHES_PER_TX,
|
|
33
27
|
MAX_NULLIFIERS_PER_TX,
|
|
28
|
+
type PrivateLog,
|
|
34
29
|
type UnconstrainedFunctionWithMembershipProof,
|
|
35
30
|
} from '@aztec/circuits.js';
|
|
36
31
|
import { type ContractArtifact, FunctionSelector } from '@aztec/foundation/abi';
|
|
@@ -56,13 +51,11 @@ export class MemoryArchiverStore implements ArchiverDataStore {
|
|
|
56
51
|
*/
|
|
57
52
|
private txEffects: InBlock<TxEffect>[] = [];
|
|
58
53
|
|
|
59
|
-
private noteEncryptedLogsPerBlock: Map<number, EncryptedNoteL2BlockL2Logs> = new Map();
|
|
60
|
-
|
|
61
54
|
private taggedLogs: Map<string, TxScopedL2Log[]> = new Map();
|
|
62
55
|
|
|
63
56
|
private logTagsPerBlock: Map<number, Fr[]> = new Map();
|
|
64
57
|
|
|
65
|
-
private
|
|
58
|
+
private privateLogsPerBlock: Map<number, PrivateLog[]> = new Map();
|
|
66
59
|
|
|
67
60
|
private unencryptedLogsPerBlock: Map<number, UnencryptedL2BlockL2Logs> = new Map();
|
|
68
61
|
|
|
@@ -232,46 +225,61 @@ export class MemoryArchiverStore implements ArchiverDataStore {
|
|
|
232
225
|
return Promise.resolve(true);
|
|
233
226
|
}
|
|
234
227
|
|
|
235
|
-
#
|
|
228
|
+
#storeTaggedLogsFromPrivate(block: L2Block): void {
|
|
229
|
+
const dataStartIndexForBlock =
|
|
230
|
+
block.header.state.partial.noteHashTree.nextAvailableLeafIndex -
|
|
231
|
+
block.body.numberOfTxsIncludingPadded * MAX_NOTE_HASHES_PER_TX;
|
|
232
|
+
block.body.txEffects.forEach((txEffect, txIndex) => {
|
|
233
|
+
const txHash = txEffect.txHash;
|
|
234
|
+
const dataStartIndexForTx = dataStartIndexForBlock + txIndex * MAX_NOTE_HASHES_PER_TX;
|
|
235
|
+
txEffect.privateLogs.forEach(log => {
|
|
236
|
+
const tag = log.fields[0];
|
|
237
|
+
const currentLogs = this.taggedLogs.get(tag.toString()) || [];
|
|
238
|
+
this.taggedLogs.set(tag.toString(), [
|
|
239
|
+
...currentLogs,
|
|
240
|
+
new TxScopedL2Log(txHash, dataStartIndexForTx, block.number, /* isFromPublic */ false, log.toBuffer()),
|
|
241
|
+
]);
|
|
242
|
+
const currentTagsInBlock = this.logTagsPerBlock.get(block.number) || [];
|
|
243
|
+
this.logTagsPerBlock.set(block.number, [...currentTagsInBlock, tag]);
|
|
244
|
+
});
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
#storeTaggedLogsFromPublic(block: L2Block): void {
|
|
236
249
|
const dataStartIndexForBlock =
|
|
237
250
|
block.header.state.partial.noteHashTree.nextAvailableLeafIndex -
|
|
238
251
|
block.body.numberOfTxsIncludingPadded * MAX_NOTE_HASHES_PER_TX;
|
|
239
|
-
block.body
|
|
252
|
+
block.body.unencryptedLogs.txLogs.forEach((txLogs, txIndex) => {
|
|
240
253
|
const txHash = block.body.txEffects[txIndex].txHash;
|
|
241
254
|
const dataStartIndexForTx = dataStartIndexForBlock + txIndex * MAX_NOTE_HASHES_PER_TX;
|
|
242
255
|
const logs = txLogs.unrollLogs();
|
|
243
256
|
logs.forEach(log => {
|
|
244
257
|
if (
|
|
245
|
-
(logType == 'noteEncryptedLogs' && log.data.length < 32) ||
|
|
246
258
|
// TODO remove when #9835 and #9836 are fixed
|
|
247
|
-
|
|
259
|
+
log.data.length <
|
|
260
|
+
32 * 33
|
|
248
261
|
) {
|
|
249
|
-
this.#log.warn(`Skipping log
|
|
262
|
+
this.#log.warn(`Skipping unencrypted log with invalid data length: ${log.data.length}`);
|
|
250
263
|
return;
|
|
251
264
|
}
|
|
252
265
|
try {
|
|
253
|
-
let tag = Fr.ZERO;
|
|
254
266
|
// TODO remove when #9835 and #9836 are fixed. The partial note logs are emitted as bytes, but encoded as Fields.
|
|
255
267
|
// This means that for every 32 bytes of payload, we only have 1 byte of data.
|
|
256
268
|
// Also, the tag is not stored in the first 32 bytes of the log, (that's the length of public fields now) but in the next 32.
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
correctedBuffer.writeUInt8(byte, i);
|
|
265
|
-
}
|
|
266
|
-
tag = new Fr(correctedBuffer);
|
|
267
|
-
} else {
|
|
268
|
-
tag = new Fr(log.data.subarray(0, 32));
|
|
269
|
+
const correctedBuffer = Buffer.alloc(32);
|
|
270
|
+
const initialOffset = 32;
|
|
271
|
+
for (let i = 0; i < 32; i++) {
|
|
272
|
+
const byte = Fr.fromBuffer(
|
|
273
|
+
log.data.subarray(i * 32 + initialOffset, i * 32 + 32 + initialOffset),
|
|
274
|
+
).toNumber();
|
|
275
|
+
correctedBuffer.writeUInt8(byte, i);
|
|
269
276
|
}
|
|
270
|
-
|
|
277
|
+
const tag = new Fr(correctedBuffer);
|
|
278
|
+
this.#log.verbose(`Storing unencrypted tagged log with tag ${tag.toString()} in block ${block.number}`);
|
|
271
279
|
const currentLogs = this.taggedLogs.get(tag.toString()) || [];
|
|
272
280
|
this.taggedLogs.set(tag.toString(), [
|
|
273
281
|
...currentLogs,
|
|
274
|
-
new TxScopedL2Log(txHash, dataStartIndexForTx, block.number,
|
|
282
|
+
new TxScopedL2Log(txHash, dataStartIndexForTx, block.number, /* isFromPublic */ true, log.data),
|
|
275
283
|
]);
|
|
276
284
|
const currentTagsInBlock = this.logTagsPerBlock.get(block.number) || [];
|
|
277
285
|
this.logTagsPerBlock.set(block.number, [...currentTagsInBlock, tag]);
|
|
@@ -289,10 +297,9 @@ export class MemoryArchiverStore implements ArchiverDataStore {
|
|
|
289
297
|
*/
|
|
290
298
|
addLogs(blocks: L2Block[]): Promise<boolean> {
|
|
291
299
|
blocks.forEach(block => {
|
|
292
|
-
void this.#
|
|
293
|
-
void this.#
|
|
294
|
-
this.
|
|
295
|
-
this.encryptedLogsPerBlock.set(block.number, block.body.encryptedLogs);
|
|
300
|
+
void this.#storeTaggedLogsFromPrivate(block);
|
|
301
|
+
void this.#storeTaggedLogsFromPublic(block);
|
|
302
|
+
this.privateLogsPerBlock.set(block.number, block.body.txEffects.map(txEffect => txEffect.privateLogs).flat());
|
|
296
303
|
this.unencryptedLogsPerBlock.set(block.number, block.body.unencryptedLogs);
|
|
297
304
|
this.contractClassLogsPerBlock.set(block.number, block.body.contractClassLogs);
|
|
298
305
|
});
|
|
@@ -308,8 +315,7 @@ export class MemoryArchiverStore implements ArchiverDataStore {
|
|
|
308
315
|
});
|
|
309
316
|
|
|
310
317
|
blocks.forEach(block => {
|
|
311
|
-
this.
|
|
312
|
-
this.noteEncryptedLogsPerBlock.delete(block.number);
|
|
318
|
+
this.privateLogsPerBlock.delete(block.number);
|
|
313
319
|
this.unencryptedLogsPerBlock.delete(block.number);
|
|
314
320
|
this.logTagsPerBlock.delete(block.number);
|
|
315
321
|
this.contractClassLogsPerBlock.delete(block.number);
|
|
@@ -471,17 +477,12 @@ export class MemoryArchiverStore implements ArchiverDataStore {
|
|
|
471
477
|
}
|
|
472
478
|
|
|
473
479
|
/**
|
|
474
|
-
*
|
|
475
|
-
* @param from -
|
|
476
|
-
* @param limit - The number of
|
|
477
|
-
* @
|
|
478
|
-
* @returns The requested logs.
|
|
480
|
+
* Retrieves all private logs from up to `limit` blocks, starting from the block number `from`.
|
|
481
|
+
* @param from - The block number from which to begin retrieving logs.
|
|
482
|
+
* @param limit - The maximum number of blocks to retrieve logs from.
|
|
483
|
+
* @returns An array of private logs from the specified range of blocks.
|
|
479
484
|
*/
|
|
480
|
-
|
|
481
|
-
from: number,
|
|
482
|
-
limit: number,
|
|
483
|
-
logType: TLogType,
|
|
484
|
-
): Promise<L2BlockL2Logs<FromLogType<TLogType>>[]> {
|
|
485
|
+
getPrivateLogs(from: number, limit: number): Promise<PrivateLog[]> {
|
|
485
486
|
if (from < INITIAL_L2_BLOCK_NUM || limit < 1) {
|
|
486
487
|
return Promise.resolve([]);
|
|
487
488
|
}
|
|
@@ -490,34 +491,19 @@ export class MemoryArchiverStore implements ArchiverDataStore {
|
|
|
490
491
|
return Promise.resolve([]);
|
|
491
492
|
}
|
|
492
493
|
|
|
493
|
-
const logMap = (() => {
|
|
494
|
-
switch (logType) {
|
|
495
|
-
case LogType.ENCRYPTED:
|
|
496
|
-
return this.encryptedLogsPerBlock;
|
|
497
|
-
case LogType.NOTEENCRYPTED:
|
|
498
|
-
return this.noteEncryptedLogsPerBlock;
|
|
499
|
-
case LogType.UNENCRYPTED:
|
|
500
|
-
default:
|
|
501
|
-
return this.unencryptedLogsPerBlock;
|
|
502
|
-
}
|
|
503
|
-
})() as Map<number, L2BlockL2Logs<FromLogType<TLogType>>>;
|
|
504
|
-
|
|
505
494
|
const startIndex = from;
|
|
506
495
|
const endIndex = startIndex + limit;
|
|
507
496
|
const upper = Math.min(endIndex, this.l2Blocks.length + INITIAL_L2_BLOCK_NUM);
|
|
508
497
|
|
|
509
|
-
const
|
|
498
|
+
const logsInBlocks = [];
|
|
510
499
|
for (let i = startIndex; i < upper; i++) {
|
|
511
|
-
const
|
|
512
|
-
if (
|
|
513
|
-
|
|
514
|
-
} else {
|
|
515
|
-
// I hate typescript sometimes
|
|
516
|
-
l.push(undefined as unknown as L2BlockL2Logs<FromLogType<TLogType>>);
|
|
500
|
+
const logs = this.privateLogsPerBlock.get(i);
|
|
501
|
+
if (logs) {
|
|
502
|
+
logsInBlocks.push(logs);
|
|
517
503
|
}
|
|
518
504
|
}
|
|
519
505
|
|
|
520
|
-
return Promise.resolve(
|
|
506
|
+
return Promise.resolve(logsInBlocks.flat());
|
|
521
507
|
}
|
|
522
508
|
|
|
523
509
|
/**
|
package/src/index.ts
CHANGED
|
@@ -1,62 +1,8 @@
|
|
|
1
|
-
import { jsonStringify } from '@aztec/foundation/json-rpc';
|
|
2
|
-
import { createDebugLogger } from '@aztec/foundation/log';
|
|
3
|
-
import { fileURLToPath } from '@aztec/foundation/url';
|
|
4
|
-
import { NoopTelemetryClient } from '@aztec/telemetry-client/noop';
|
|
5
|
-
|
|
6
|
-
import { createPublicClient, http } from 'viem';
|
|
7
|
-
import { localhost } from 'viem/chains';
|
|
8
|
-
|
|
9
|
-
import { Archiver, getArchiverConfigFromEnv } from './archiver/index.js';
|
|
10
|
-
import { ArchiverInstrumentation } from './archiver/instrumentation.js';
|
|
11
|
-
import { MemoryArchiverStore } from './archiver/memory_archiver_store/memory_archiver_store.js';
|
|
12
|
-
|
|
13
1
|
export * from './archiver/index.js';
|
|
14
|
-
export * from './rpc/index.js';
|
|
15
2
|
export * from './factory.js';
|
|
3
|
+
export * from './rpc/index.js';
|
|
16
4
|
|
|
17
|
-
export {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* A function which instantiates and starts Archiver.
|
|
23
|
-
*/
|
|
24
|
-
// eslint-disable-next-line require-await
|
|
25
|
-
async function main() {
|
|
26
|
-
const config = getArchiverConfigFromEnv();
|
|
27
|
-
const { l1RpcUrl: rpcUrl, l1Contracts } = config;
|
|
28
|
-
|
|
29
|
-
log.info(`Starting archiver in main(): ${jsonStringify(config)}`);
|
|
30
|
-
const publicClient = createPublicClient({
|
|
31
|
-
chain: localhost,
|
|
32
|
-
transport: http(rpcUrl),
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
const archiverStore = new MemoryArchiverStore(1000);
|
|
36
|
-
|
|
37
|
-
const archiver = new Archiver(
|
|
38
|
-
publicClient,
|
|
39
|
-
l1Contracts.rollupAddress,
|
|
40
|
-
l1Contracts.inboxAddress,
|
|
41
|
-
l1Contracts.registryAddress,
|
|
42
|
-
archiverStore,
|
|
43
|
-
1000,
|
|
44
|
-
new ArchiverInstrumentation(new NoopTelemetryClient()),
|
|
45
|
-
);
|
|
46
|
-
|
|
47
|
-
const shutdown = async () => {
|
|
48
|
-
await archiver.stop();
|
|
49
|
-
process.exit(0);
|
|
50
|
-
};
|
|
51
|
-
process.once('SIGINT', shutdown);
|
|
52
|
-
process.once('SIGTERM', shutdown);
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
// See https://twitter.com/Rich_Harris/status/1355289863130673153
|
|
56
|
-
if (process.argv[1] === fileURLToPath(import.meta.url).replace(/\/index\.js$/, '')) {
|
|
57
|
-
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
|
58
|
-
main().catch(err => {
|
|
59
|
-
log.error(err);
|
|
60
|
-
process.exit(1);
|
|
61
|
-
});
|
|
62
|
-
}
|
|
5
|
+
export {
|
|
6
|
+
retrieveBlocksFromRollup as retrieveBlockFromRollup,
|
|
7
|
+
retrieveL2ProofVerifiedEvents,
|
|
8
|
+
} from './archiver/data_retrieval.js';
|
|
@@ -7,12 +7,11 @@ import {
|
|
|
7
7
|
TxReceipt,
|
|
8
8
|
TxStatus,
|
|
9
9
|
} from '@aztec/circuit-types';
|
|
10
|
+
import { getSlotRangeForEpoch } from '@aztec/circuit-types';
|
|
10
11
|
import { EthAddress, type Header } from '@aztec/circuits.js';
|
|
11
12
|
import { DefaultL1ContractsConfig } from '@aztec/ethereum';
|
|
12
13
|
import { createDebugLogger } from '@aztec/foundation/log';
|
|
13
14
|
|
|
14
|
-
import { getSlotRangeForEpoch } from '../archiver/epoch_helpers.js';
|
|
15
|
-
|
|
16
15
|
/**
|
|
17
16
|
* A mocked implementation of L2BlockSource to be used in tests.
|
|
18
17
|
*/
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
export type EpochConstants = {
|
|
2
|
-
l1GenesisBlock: bigint;
|
|
3
|
-
l1GenesisTime: bigint;
|
|
4
|
-
epochDuration: number;
|
|
5
|
-
slotDuration: number;
|
|
6
|
-
};
|
|
7
|
-
/** Returns the slot number for a given timestamp. */
|
|
8
|
-
export declare function getSlotAtTimestamp(ts: bigint, constants: Pick<EpochConstants, 'l1GenesisTime' | 'slotDuration'>): bigint;
|
|
9
|
-
/** Returns the epoch number for a given timestamp. */
|
|
10
|
-
export declare function getEpochNumberAtTimestamp(ts: bigint, constants: Pick<EpochConstants, 'epochDuration' | 'slotDuration' | 'l1GenesisTime'>): bigint;
|
|
11
|
-
/** Returns the range of L2 slots (inclusive) for a given epoch number. */
|
|
12
|
-
export declare function getSlotRangeForEpoch(epochNumber: bigint, constants: Pick<EpochConstants, 'epochDuration'>): bigint[];
|
|
13
|
-
/** Returns the range of L1 timestamps (inclusive) for a given epoch number. */
|
|
14
|
-
export declare function getTimestampRangeForEpoch(epochNumber: bigint, constants: Pick<EpochConstants, 'l1GenesisTime' | 'slotDuration' | 'epochDuration'>): bigint[];
|
|
15
|
-
/**
|
|
16
|
-
* Returns the range of L1 blocks (inclusive) for a given epoch number.
|
|
17
|
-
* @remarks This assumes no time warp has happened.
|
|
18
|
-
*/
|
|
19
|
-
export declare function getL1BlockRangeForEpoch(epochNumber: bigint, constants: Pick<EpochConstants, 'l1GenesisBlock' | 'epochDuration' | 'slotDuration'>): bigint[];
|
|
20
|
-
//# sourceMappingURL=epoch_helpers.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"epoch_helpers.d.ts","sourceRoot":"","sources":["../../src/archiver/epoch_helpers.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,cAAc,GAAG;IAC3B,cAAc,EAAE,MAAM,CAAC;IACvB,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF,qDAAqD;AACrD,wBAAgB,kBAAkB,CAAC,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,CAAC,cAAc,EAAE,eAAe,GAAG,cAAc,CAAC,UAE/G;AAED,sDAAsD;AACtD,wBAAgB,yBAAyB,CACvC,EAAE,EAAE,MAAM,EACV,SAAS,EAAE,IAAI,CAAC,cAAc,EAAE,eAAe,GAAG,cAAc,GAAG,eAAe,CAAC,UAGpF;AAED,0EAA0E;AAC1E,wBAAgB,oBAAoB,CAAC,WAAW,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,CAAC,cAAc,EAAE,eAAe,CAAC,YAGzG;AAED,+EAA+E;AAC/E,wBAAgB,yBAAyB,CACvC,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,IAAI,CAAC,cAAc,EAAE,eAAe,GAAG,cAAc,GAAG,eAAe,CAAC,YAOpF;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,CACrC,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,IAAI,CAAC,cAAc,EAAE,gBAAgB,GAAG,eAAe,GAAG,cAAc,CAAC,YAOrF"}
|