@aztec/archiver 0.26.6 → 0.27.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/README.md +2 -3
- package/dest/archiver/archiver.d.ts +12 -16
- package/dest/archiver/archiver.d.ts.map +1 -1
- package/dest/archiver/archiver.js +38 -36
- package/dest/archiver/archiver_store.d.ts +18 -21
- 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 +46 -90
- package/dest/archiver/config.d.ts.map +1 -1
- package/dest/archiver/config.js +2 -5
- package/dest/archiver/data_retrieval.d.ts +10 -12
- package/dest/archiver/data_retrieval.d.ts.map +1 -1
- package/dest/archiver/data_retrieval.js +23 -22
- package/dest/archiver/eth_log_handlers.d.ts +17 -20
- package/dest/archiver/eth_log_handlers.d.ts.map +1 -1
- package/dest/archiver/eth_log_handlers.js +35 -52
- package/dest/archiver/kv_archiver_store/block_store.d.ts.map +1 -1
- package/dest/archiver/kv_archiver_store/block_store.js +1 -9
- package/dest/archiver/kv_archiver_store/contract_store.d.ts +1 -21
- package/dest/archiver/kv_archiver_store/contract_store.d.ts.map +1 -1
- package/dest/archiver/kv_archiver_store/contract_store.js +1 -36
- package/dest/archiver/kv_archiver_store/kv_archiver_store.d.ts +14 -21
- package/dest/archiver/kv_archiver_store/kv_archiver_store.d.ts.map +1 -1
- package/dest/archiver/kv_archiver_store/kv_archiver_store.js +25 -28
- package/dest/archiver/kv_archiver_store/message_store.d.ts +11 -1
- package/dest/archiver/kv_archiver_store/message_store.d.ts.map +1 -1
- package/dest/archiver/kv_archiver_store/message_store.js +57 -5
- package/dest/archiver/memory_archiver_store/l1_to_l2_message_store.d.ts +18 -1
- package/dest/archiver/memory_archiver_store/l1_to_l2_message_store.d.ts.map +1 -1
- package/dest/archiver/memory_archiver_store/l1_to_l2_message_store.js +48 -1
- package/dest/archiver/memory_archiver_store/memory_archiver_store.d.ts +18 -21
- package/dest/archiver/memory_archiver_store/memory_archiver_store.d.ts.map +1 -1
- package/dest/archiver/memory_archiver_store/memory_archiver_store.js +32 -45
- package/dest/index.d.ts.map +1 -1
- package/dest/index.js +15 -3
- package/package.json +9 -9
- package/src/archiver/archiver.ts +46 -46
- package/src/archiver/archiver_store.ts +21 -24
- package/src/archiver/archiver_store_test_suite.ts +54 -115
- package/src/archiver/config.ts +0 -4
- package/src/archiver/data_retrieval.ts +30 -35
- package/src/archiver/eth_log_handlers.ts +42 -74
- package/src/archiver/kv_archiver_store/block_store.ts +0 -10
- package/src/archiver/kv_archiver_store/contract_store.ts +1 -44
- package/src/archiver/kv_archiver_store/kv_archiver_store.ts +26 -31
- package/src/archiver/kv_archiver_store/message_store.ts +60 -3
- package/src/archiver/memory_archiver_store/l1_to_l2_message_store.ts +48 -1
- package/src/archiver/memory_archiver_store/memory_archiver_store.ts +36 -48
- package/src/index.ts +15 -2
|
@@ -1,18 +1,18 @@
|
|
|
1
|
-
import { Body,
|
|
1
|
+
import { Body, L1ToL2Message, NewInboxLeaf } from '@aztec/circuit-types';
|
|
2
2
|
import { AppendOnlyTreeSnapshot, Fr, Header } from '@aztec/circuits.js';
|
|
3
3
|
import { EthAddress } from '@aztec/foundation/eth-address';
|
|
4
4
|
|
|
5
5
|
import { PublicClient } from 'viem';
|
|
6
6
|
|
|
7
7
|
import {
|
|
8
|
-
getContractDeploymentLogs,
|
|
9
8
|
getL1ToL2MessageCancelledLogs,
|
|
10
9
|
getL2BlockProcessedLogs,
|
|
10
|
+
getLeafInsertedLogs,
|
|
11
11
|
getPendingL1ToL2MessageLogs,
|
|
12
12
|
getTxsPublishedLogs,
|
|
13
13
|
processCancelledL1ToL2MessagesLogs,
|
|
14
|
-
processContractDeploymentLogs,
|
|
15
14
|
processL2BlockProcessedLogs,
|
|
15
|
+
processLeafInsertedLogs,
|
|
16
16
|
processPendingL1ToL2MessageAddedLogs,
|
|
17
17
|
processTxsPublishedLogs,
|
|
18
18
|
} from './eth_log_handlers.js';
|
|
@@ -116,78 +116,72 @@ export async function retrieveBlockBodiesFromAvailabilityOracle(
|
|
|
116
116
|
}
|
|
117
117
|
|
|
118
118
|
/**
|
|
119
|
-
*
|
|
119
|
+
* Fetch new pending L1 to L2 messages.
|
|
120
120
|
* @param publicClient - The viem public client to use for transaction retrieval.
|
|
121
|
-
* @param
|
|
121
|
+
* @param inboxAddress - The address of the inbox contract to fetch messages from.
|
|
122
122
|
* @param blockUntilSynced - If true, blocks until the archiver has fully synced.
|
|
123
123
|
* @param searchStartBlock - The block number to use for starting the search.
|
|
124
124
|
* @param searchEndBlock - The highest block number that we should search up to.
|
|
125
|
-
* @
|
|
126
|
-
* @returns An array of ExtendedContractData and their equivalent L2 Block number along with the next eth block to search from..
|
|
125
|
+
* @returns An array of L1ToL2Message and next eth block to search from.
|
|
127
126
|
*/
|
|
128
|
-
export async function
|
|
127
|
+
export async function retrieveNewPendingL1ToL2Messages(
|
|
129
128
|
publicClient: PublicClient,
|
|
130
|
-
|
|
129
|
+
inboxAddress: EthAddress,
|
|
131
130
|
blockUntilSynced: boolean,
|
|
132
131
|
searchStartBlock: bigint,
|
|
133
132
|
searchEndBlock: bigint,
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
let retrievedNewContracts: [ExtendedContractData[], number][] = [];
|
|
133
|
+
): Promise<DataRetrieval<[L1ToL2Message, bigint]>> {
|
|
134
|
+
const retrievedNewL1ToL2Messages: [L1ToL2Message, bigint][] = [];
|
|
137
135
|
do {
|
|
138
136
|
if (searchStartBlock > searchEndBlock) {
|
|
139
137
|
break;
|
|
140
138
|
}
|
|
141
|
-
const
|
|
139
|
+
const newL1ToL2MessageLogs = await getPendingL1ToL2MessageLogs(
|
|
142
140
|
publicClient,
|
|
143
|
-
|
|
141
|
+
inboxAddress,
|
|
144
142
|
searchStartBlock,
|
|
145
143
|
searchEndBlock,
|
|
146
144
|
);
|
|
147
|
-
if (
|
|
145
|
+
if (newL1ToL2MessageLogs.length === 0) {
|
|
148
146
|
break;
|
|
149
147
|
}
|
|
150
|
-
const
|
|
151
|
-
|
|
152
|
-
|
|
148
|
+
const newL1ToL2Messages = processPendingL1ToL2MessageAddedLogs(newL1ToL2MessageLogs);
|
|
149
|
+
retrievedNewL1ToL2Messages.push(...newL1ToL2Messages);
|
|
150
|
+
// handles the case when there are no new messages:
|
|
151
|
+
searchStartBlock = (newL1ToL2MessageLogs.findLast(msgLog => !!msgLog)?.blockNumber || searchStartBlock) + 1n;
|
|
153
152
|
} while (blockUntilSynced && searchStartBlock <= searchEndBlock);
|
|
154
|
-
return { nextEthBlockNumber: searchStartBlock, retrievedData:
|
|
153
|
+
return { nextEthBlockNumber: searchStartBlock, retrievedData: retrievedNewL1ToL2Messages };
|
|
155
154
|
}
|
|
156
155
|
|
|
157
156
|
/**
|
|
158
|
-
* Fetch new
|
|
157
|
+
* Fetch new L1 to L2 messages.
|
|
159
158
|
* @param publicClient - The viem public client to use for transaction retrieval.
|
|
160
|
-
* @param
|
|
159
|
+
* @param newInboxAddress - The address of the inbox contract to fetch messages from.
|
|
161
160
|
* @param blockUntilSynced - If true, blocks until the archiver has fully synced.
|
|
162
161
|
* @param searchStartBlock - The block number to use for starting the search.
|
|
163
162
|
* @param searchEndBlock - The highest block number that we should search up to.
|
|
164
|
-
* @returns An array of
|
|
163
|
+
* @returns An array of NewInboxLeaf and next eth block to search from.
|
|
165
164
|
*/
|
|
166
|
-
export async function
|
|
165
|
+
export async function retrieveNewL1ToL2Messages(
|
|
167
166
|
publicClient: PublicClient,
|
|
168
|
-
|
|
167
|
+
newInboxAddress: EthAddress,
|
|
169
168
|
blockUntilSynced: boolean,
|
|
170
169
|
searchStartBlock: bigint,
|
|
171
170
|
searchEndBlock: bigint,
|
|
172
|
-
): Promise<DataRetrieval<
|
|
173
|
-
const retrievedNewL1ToL2Messages: [
|
|
171
|
+
): Promise<DataRetrieval<NewInboxLeaf>> {
|
|
172
|
+
const retrievedNewL1ToL2Messages: NewInboxLeaf[] = [];
|
|
174
173
|
do {
|
|
175
174
|
if (searchStartBlock > searchEndBlock) {
|
|
176
175
|
break;
|
|
177
176
|
}
|
|
178
|
-
const
|
|
179
|
-
|
|
180
|
-
inboxAddress,
|
|
181
|
-
searchStartBlock,
|
|
182
|
-
searchEndBlock,
|
|
183
|
-
);
|
|
184
|
-
if (newL1ToL2MessageLogs.length === 0) {
|
|
177
|
+
const leafInsertedLogs = await getLeafInsertedLogs(publicClient, newInboxAddress, searchStartBlock, searchEndBlock);
|
|
178
|
+
if (leafInsertedLogs.length === 0) {
|
|
185
179
|
break;
|
|
186
180
|
}
|
|
187
|
-
const newL1ToL2Messages =
|
|
181
|
+
const newL1ToL2Messages = processLeafInsertedLogs(leafInsertedLogs);
|
|
188
182
|
retrievedNewL1ToL2Messages.push(...newL1ToL2Messages);
|
|
189
183
|
// handles the case when there are no new messages:
|
|
190
|
-
searchStartBlock = (
|
|
184
|
+
searchStartBlock = (leafInsertedLogs.findLast(msgLog => !!msgLog)?.blockNumber || searchStartBlock) + 1n;
|
|
191
185
|
} while (blockUntilSynced && searchStartBlock <= searchEndBlock);
|
|
192
186
|
return { nextEthBlockNumber: searchStartBlock, retrievedData: retrievedNewL1ToL2Messages };
|
|
193
187
|
}
|
|
@@ -200,6 +194,7 @@ export async function retrieveNewPendingL1ToL2Messages(
|
|
|
200
194
|
* @param searchStartBlock - The block number to use for starting the search.
|
|
201
195
|
* @param searchEndBlock - The highest block number that we should search up to.
|
|
202
196
|
* @returns An array of entry keys that were cancelled and next eth block to search from.
|
|
197
|
+
* TODO(#4492): Nuke the following when purging the old inbox
|
|
203
198
|
*/
|
|
204
199
|
export async function retrieveNewCancelledL1ToL2Messages(
|
|
205
200
|
publicClient: PublicClient,
|
|
@@ -1,21 +1,29 @@
|
|
|
1
|
-
import {
|
|
2
|
-
Body,
|
|
3
|
-
ContractData,
|
|
4
|
-
EncodedContractFunction,
|
|
5
|
-
ExtendedContractData,
|
|
6
|
-
L1Actor,
|
|
7
|
-
L1ToL2Message,
|
|
8
|
-
L2Actor,
|
|
9
|
-
} from '@aztec/circuit-types';
|
|
1
|
+
import { Body, L1Actor, L1ToL2Message, L2Actor, NewInboxLeaf } from '@aztec/circuit-types';
|
|
10
2
|
import { AppendOnlyTreeSnapshot, Header } from '@aztec/circuits.js';
|
|
11
3
|
import { AztecAddress } from '@aztec/foundation/aztec-address';
|
|
12
4
|
import { EthAddress } from '@aztec/foundation/eth-address';
|
|
13
5
|
import { Fr } from '@aztec/foundation/fields';
|
|
14
|
-
import {
|
|
15
|
-
import { AvailabilityOracleAbi,
|
|
6
|
+
import { numToUInt32BE } from '@aztec/foundation/serialize';
|
|
7
|
+
import { AvailabilityOracleAbi, InboxAbi, NewInboxAbi, RollupAbi } from '@aztec/l1-artifacts';
|
|
16
8
|
|
|
17
9
|
import { Hex, Log, PublicClient, decodeFunctionData, getAbiItem, getAddress, hexToBytes } from 'viem';
|
|
18
10
|
|
|
11
|
+
/**
|
|
12
|
+
* Processes newly received LeafInserted (L1 to L2) logs.
|
|
13
|
+
* @param logs - LeafInserted logs.
|
|
14
|
+
* @returns Array of all processed LeafInserted logs
|
|
15
|
+
*/
|
|
16
|
+
export function processLeafInsertedLogs(
|
|
17
|
+
logs: Log<bigint, number, false, undefined, true, typeof NewInboxAbi, 'LeafInserted'>[],
|
|
18
|
+
): NewInboxLeaf[] {
|
|
19
|
+
const leaves: NewInboxLeaf[] = [];
|
|
20
|
+
for (const log of logs) {
|
|
21
|
+
const { blockNumber, index, value } = log.args;
|
|
22
|
+
leaves.push(new NewInboxLeaf(blockNumber, index, Buffer.from(hexToBytes(value))));
|
|
23
|
+
}
|
|
24
|
+
return leaves;
|
|
25
|
+
}
|
|
26
|
+
|
|
19
27
|
/**
|
|
20
28
|
* Processes newly received MessageAdded (L1 to L2) logs.
|
|
21
29
|
* @param logs - MessageAdded logs.
|
|
@@ -227,24 +235,24 @@ export function getTxsPublishedLogs(
|
|
|
227
235
|
}
|
|
228
236
|
|
|
229
237
|
/**
|
|
230
|
-
*
|
|
238
|
+
* Get relevant `MessageAdded` logs emitted by Inbox on chain.
|
|
231
239
|
* @param publicClient - The viem public client to use for transaction retrieval.
|
|
232
|
-
* @param
|
|
240
|
+
* @param inboxAddress - The address of the inbox contract.
|
|
233
241
|
* @param fromBlock - First block to get logs from (inclusive).
|
|
234
242
|
* @param toBlock - Last block to get logs from (inclusive).
|
|
235
|
-
* @returns An array of `
|
|
243
|
+
* @returns An array of `MessageAdded` logs.
|
|
236
244
|
*/
|
|
237
|
-
export function
|
|
245
|
+
export function getPendingL1ToL2MessageLogs(
|
|
238
246
|
publicClient: PublicClient,
|
|
239
|
-
|
|
247
|
+
inboxAddress: EthAddress,
|
|
240
248
|
fromBlock: bigint,
|
|
241
249
|
toBlock: bigint,
|
|
242
|
-
): Promise<Log<bigint, number, false, undefined, true, typeof
|
|
250
|
+
): Promise<Log<bigint, number, false, undefined, true, typeof InboxAbi, 'MessageAdded'>[]> {
|
|
243
251
|
return publicClient.getLogs({
|
|
244
|
-
address: getAddress(
|
|
252
|
+
address: getAddress(inboxAddress.toString()),
|
|
245
253
|
event: getAbiItem({
|
|
246
|
-
abi:
|
|
247
|
-
name: '
|
|
254
|
+
abi: InboxAbi,
|
|
255
|
+
name: 'MessageAdded',
|
|
248
256
|
}),
|
|
249
257
|
fromBlock,
|
|
250
258
|
toBlock: toBlock + 1n, // the toBlock argument in getLogs is exclusive
|
|
@@ -252,64 +260,24 @@ export function getContractDeploymentLogs(
|
|
|
252
260
|
}
|
|
253
261
|
|
|
254
262
|
/**
|
|
255
|
-
*
|
|
256
|
-
* @param blockNumberToBodyHash - A mapping from block number to relevant body hash.
|
|
257
|
-
* @param logs - ContractDeployment logs.
|
|
258
|
-
* @returns The set of retrieved extended contract data items.
|
|
259
|
-
*/
|
|
260
|
-
export function processContractDeploymentLogs(
|
|
261
|
-
blockNumberToBodyHash: { [key: number]: Buffer | undefined },
|
|
262
|
-
logs: Log<bigint, number, false, undefined, true, typeof ContractDeploymentEmitterAbi, 'ContractDeployment'>[],
|
|
263
|
-
): [ExtendedContractData[], number][] {
|
|
264
|
-
const extendedContractData: [ExtendedContractData[], number][] = [];
|
|
265
|
-
for (let i = 0; i < logs.length; i++) {
|
|
266
|
-
const log = logs[i];
|
|
267
|
-
const l2BlockNum = Number(log.args.l2BlockNum);
|
|
268
|
-
const blockHash = Buffer.from(hexToBytes(log.args.l2BlockHash));
|
|
269
|
-
const expectedBlockHash = blockNumberToBodyHash[l2BlockNum];
|
|
270
|
-
if (expectedBlockHash === undefined || !blockHash.equals(expectedBlockHash)) {
|
|
271
|
-
continue;
|
|
272
|
-
}
|
|
273
|
-
const publicFnsReader = BufferReader.asReader(Buffer.from(log.args.acir.slice(2), 'hex'));
|
|
274
|
-
const contractClassId = Fr.fromBuffer(Buffer.from(hexToBytes(log.args.contractClassId)));
|
|
275
|
-
const saltedInitializationHash = Fr.fromBuffer(Buffer.from(hexToBytes(log.args.saltedInitializationHash)));
|
|
276
|
-
const publicKeyHash = Fr.fromBuffer(Buffer.from(hexToBytes(log.args.publicKeyHash)));
|
|
277
|
-
|
|
278
|
-
const contractData = new ExtendedContractData(
|
|
279
|
-
new ContractData(AztecAddress.fromString(log.args.aztecAddress), EthAddress.fromString(log.args.portalAddress)),
|
|
280
|
-
publicFnsReader.readVector(EncodedContractFunction),
|
|
281
|
-
contractClassId,
|
|
282
|
-
saltedInitializationHash,
|
|
283
|
-
publicKeyHash,
|
|
284
|
-
);
|
|
285
|
-
if (extendedContractData[i]) {
|
|
286
|
-
extendedContractData[i][0].push(contractData);
|
|
287
|
-
} else {
|
|
288
|
-
extendedContractData[i] = [[contractData], l2BlockNum];
|
|
289
|
-
}
|
|
290
|
-
}
|
|
291
|
-
return extendedContractData;
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
/**
|
|
295
|
-
* Get relevant `MessageAdded` logs emitted by Inbox on chain.
|
|
263
|
+
* Get relevant `L1ToL2MessageCancelled` logs emitted by Inbox on chain when pending messages are cancelled
|
|
296
264
|
* @param publicClient - The viem public client to use for transaction retrieval.
|
|
297
265
|
* @param inboxAddress - The address of the inbox contract.
|
|
298
266
|
* @param fromBlock - First block to get logs from (inclusive).
|
|
299
267
|
* @param toBlock - Last block to get logs from (inclusive).
|
|
300
|
-
* @returns An array of `
|
|
268
|
+
* @returns An array of `L1ToL2MessageCancelled` logs.
|
|
301
269
|
*/
|
|
302
|
-
export function
|
|
270
|
+
export function getL1ToL2MessageCancelledLogs(
|
|
303
271
|
publicClient: PublicClient,
|
|
304
272
|
inboxAddress: EthAddress,
|
|
305
273
|
fromBlock: bigint,
|
|
306
274
|
toBlock: bigint,
|
|
307
|
-
): Promise<Log<bigint, number, false, undefined, true, typeof InboxAbi, '
|
|
275
|
+
): Promise<Log<bigint, number, false, undefined, true, typeof InboxAbi, 'L1ToL2MessageCancelled'>[]> {
|
|
308
276
|
return publicClient.getLogs({
|
|
309
277
|
address: getAddress(inboxAddress.toString()),
|
|
310
278
|
event: getAbiItem({
|
|
311
279
|
abi: InboxAbi,
|
|
312
|
-
name: '
|
|
280
|
+
name: 'L1ToL2MessageCancelled',
|
|
313
281
|
}),
|
|
314
282
|
fromBlock,
|
|
315
283
|
toBlock: toBlock + 1n, // the toBlock argument in getLogs is exclusive
|
|
@@ -317,24 +285,24 @@ export function getPendingL1ToL2MessageLogs(
|
|
|
317
285
|
}
|
|
318
286
|
|
|
319
287
|
/**
|
|
320
|
-
* Get relevant `
|
|
288
|
+
* Get relevant `LeafInserted` logs emitted by NewInbox on chain.
|
|
321
289
|
* @param publicClient - The viem public client to use for transaction retrieval.
|
|
322
|
-
* @param
|
|
290
|
+
* @param newInboxAddress - The address of the new inbox contract.
|
|
323
291
|
* @param fromBlock - First block to get logs from (inclusive).
|
|
324
292
|
* @param toBlock - Last block to get logs from (inclusive).
|
|
325
|
-
* @returns An array of `
|
|
293
|
+
* @returns An array of `LeafInserted` logs.
|
|
326
294
|
*/
|
|
327
|
-
export function
|
|
295
|
+
export function getLeafInsertedLogs(
|
|
328
296
|
publicClient: PublicClient,
|
|
329
|
-
|
|
297
|
+
newInboxAddress: EthAddress,
|
|
330
298
|
fromBlock: bigint,
|
|
331
299
|
toBlock: bigint,
|
|
332
|
-
): Promise<Log<bigint, number, false, undefined, true, typeof
|
|
300
|
+
): Promise<Log<bigint, number, false, undefined, true, typeof NewInboxAbi, 'LeafInserted'>[]> {
|
|
333
301
|
return publicClient.getLogs({
|
|
334
|
-
address: getAddress(
|
|
302
|
+
address: getAddress(newInboxAddress.toString()),
|
|
335
303
|
event: getAbiItem({
|
|
336
|
-
abi:
|
|
337
|
-
name: '
|
|
304
|
+
abi: NewInboxAbi,
|
|
305
|
+
name: 'LeafInserted',
|
|
338
306
|
}),
|
|
339
307
|
fromBlock,
|
|
340
308
|
toBlock: toBlock + 1n, // the toBlock argument in getLogs is exclusive
|
|
@@ -55,16 +55,6 @@ export class BlockStore {
|
|
|
55
55
|
block.getTxs().forEach((tx, i) => {
|
|
56
56
|
void this.#txIndex.set(tx.txHash.toString(), [block.number, i]);
|
|
57
57
|
});
|
|
58
|
-
|
|
59
|
-
block.body.txEffects
|
|
60
|
-
.flatMap(txEffect => txEffect.contractData)
|
|
61
|
-
.forEach((contractData, i) => {
|
|
62
|
-
if (contractData.contractAddress.isZero()) {
|
|
63
|
-
return;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
void this.#contractIndex.set(contractData.contractAddress.toString(), [block.number, i]);
|
|
67
|
-
});
|
|
68
58
|
}
|
|
69
59
|
|
|
70
60
|
return true;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ExtendedContractData } from '@aztec/circuit-types';
|
|
2
2
|
import { AztecAddress } from '@aztec/foundation/aztec-address';
|
|
3
3
|
import { createDebugLogger } from '@aztec/foundation/log';
|
|
4
4
|
import { AztecKVStore, AztecMap } from '@aztec/kv-store';
|
|
@@ -52,47 +52,4 @@ export class ContractStore {
|
|
|
52
52
|
|
|
53
53
|
return undefined;
|
|
54
54
|
}
|
|
55
|
-
|
|
56
|
-
/**
|
|
57
|
-
* Lookup all extended contract data in an L2 block.
|
|
58
|
-
* @param blockNumber - The block number to get all contract data from.
|
|
59
|
-
* @returns All extended contract data in the block (if found).
|
|
60
|
-
*/
|
|
61
|
-
getExtendedContractDataInBlock(blockNumber: number): Array<ExtendedContractData> {
|
|
62
|
-
return (this.#extendedContractData.get(blockNumber) ?? []).map(contract =>
|
|
63
|
-
ExtendedContractData.fromBuffer(contract),
|
|
64
|
-
);
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
/**
|
|
68
|
-
* Get basic info for an L2 contract.
|
|
69
|
-
* Contains contract address & the ethereum portal address.
|
|
70
|
-
* @param contractAddress - The contract data address.
|
|
71
|
-
* @returns ContractData with the portal address (if we didn't throw an error).
|
|
72
|
-
*/
|
|
73
|
-
getContractData(contractAddress: AztecAddress): ContractData | undefined {
|
|
74
|
-
const [blockNumber, index] = this.#blockStore.getContractLocation(contractAddress) ?? [];
|
|
75
|
-
if (typeof blockNumber !== 'number' || typeof index !== 'number') {
|
|
76
|
-
return undefined;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
const block = this.#blockStore.getBlock(blockNumber);
|
|
80
|
-
|
|
81
|
-
if (block?.body.txEffects[index].contractData.length !== 1) {
|
|
82
|
-
throw new Error(`Contract data at block: ${blockNumber}, tx: ${index} does not have length of 1`);
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
return block?.body.txEffects[index].contractData[0];
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
/**
|
|
89
|
-
* Get basic info for an all L2 contracts deployed in a block.
|
|
90
|
-
* Contains contract address & the ethereum portal address.
|
|
91
|
-
* @param blockNumber - Number of the L2 block where contracts were deployed.
|
|
92
|
-
* @returns ContractData with the portal address (if we didn't throw an error).
|
|
93
|
-
*/
|
|
94
|
-
getContractDataInBlock(blockNumber: number): ContractData[] {
|
|
95
|
-
const block = this.#blockStore.getBlock(blockNumber);
|
|
96
|
-
return block?.body.txEffects.flatMap(txEffect => txEffect.contractData) ?? [];
|
|
97
|
-
}
|
|
98
55
|
}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import {
|
|
2
2
|
Body,
|
|
3
|
-
ContractData,
|
|
4
3
|
ExtendedContractData,
|
|
5
4
|
GetUnencryptedLogsResponse,
|
|
6
5
|
L1ToL2Message,
|
|
@@ -8,6 +7,7 @@ import {
|
|
|
8
7
|
L2BlockL2Logs,
|
|
9
8
|
LogFilter,
|
|
10
9
|
LogType,
|
|
10
|
+
NewInboxLeaf,
|
|
11
11
|
TxEffect,
|
|
12
12
|
TxHash,
|
|
13
13
|
TxReceipt,
|
|
@@ -148,6 +148,16 @@ export class KVArchiverDataStore implements ArchiverDataStore {
|
|
|
148
148
|
return this.#logStore.addLogs(encryptedLogs, unencryptedLogs, blockNumber);
|
|
149
149
|
}
|
|
150
150
|
|
|
151
|
+
/**
|
|
152
|
+
* Append new L1 to L2 messages to the store.
|
|
153
|
+
* @param messages - The L1 to L2 messages to be added to the store.
|
|
154
|
+
* @param lastMessageL1BlockNumber - The L1 block number in which the last message was emitted.
|
|
155
|
+
* @returns True if the operation is successful.
|
|
156
|
+
*/
|
|
157
|
+
addNewL1ToL2Messages(messages: NewInboxLeaf[], lastMessageL1BlockNumber: bigint): Promise<boolean> {
|
|
158
|
+
return Promise.resolve(this.#messageStore.addNewL1ToL2Messages(messages, lastMessageL1BlockNumber));
|
|
159
|
+
}
|
|
160
|
+
|
|
151
161
|
/**
|
|
152
162
|
* Append new pending L1 to L2 messages to the store.
|
|
153
163
|
* @param messages - The L1 to L2 messages to be added to the store.
|
|
@@ -201,6 +211,19 @@ export class KVArchiverDataStore implements ArchiverDataStore {
|
|
|
201
211
|
}
|
|
202
212
|
}
|
|
203
213
|
|
|
214
|
+
/**
|
|
215
|
+
* Gets new L1 to L2 message (to be) included in a given block.
|
|
216
|
+
* @param blockNumber - L2 block number to get messages for.
|
|
217
|
+
* @returns The L1 to L2 messages/leaves of the messages subtree (throws if not found).
|
|
218
|
+
*/
|
|
219
|
+
getNewL1ToL2Messages(blockNumber: bigint): Promise<Buffer[]> {
|
|
220
|
+
try {
|
|
221
|
+
return Promise.resolve(this.#messageStore.getNewL1ToL2Messages(blockNumber));
|
|
222
|
+
} catch (err) {
|
|
223
|
+
return Promise.reject(err);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
204
227
|
/**
|
|
205
228
|
* Gets up to `limit` amount of logs starting from `from`.
|
|
206
229
|
* @param start - Number of the L2 block to which corresponds the first logs to be returned.
|
|
@@ -248,35 +271,6 @@ export class KVArchiverDataStore implements ArchiverDataStore {
|
|
|
248
271
|
return Promise.resolve(this.#contractStore.getExtendedContractData(contractAddress));
|
|
249
272
|
}
|
|
250
273
|
|
|
251
|
-
/**
|
|
252
|
-
* Lookup all extended contract data in an L2 block.
|
|
253
|
-
* @param blockNumber - The block number to get all contract data from.
|
|
254
|
-
* @returns All extended contract data in the block (if found).
|
|
255
|
-
*/
|
|
256
|
-
getExtendedContractDataInBlock(blockNumber: number): Promise<ExtendedContractData[]> {
|
|
257
|
-
return Promise.resolve(Array.from(this.#contractStore.getExtendedContractDataInBlock(blockNumber)));
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
/**
|
|
261
|
-
* Get basic info for an L2 contract.
|
|
262
|
-
* Contains contract address & the ethereum portal address.
|
|
263
|
-
* @param contractAddress - The contract data address.
|
|
264
|
-
* @returns ContractData with the portal address (if we didn't throw an error).
|
|
265
|
-
*/
|
|
266
|
-
getContractData(contractAddress: AztecAddress): Promise<ContractData | undefined> {
|
|
267
|
-
return Promise.resolve(this.#contractStore.getContractData(contractAddress));
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
/**
|
|
271
|
-
* Get basic info for an all L2 contracts deployed in a block.
|
|
272
|
-
* Contains contract address & the ethereum portal address.
|
|
273
|
-
* @param blockNumber - Number of the L2 block where contracts were deployed.
|
|
274
|
-
* @returns ContractData with the portal address (if we didn't throw an error).
|
|
275
|
-
*/
|
|
276
|
-
getContractDataInBlock(blockNumber: number): Promise<ContractData[]> {
|
|
277
|
-
return Promise.resolve(Array.from(this.#contractStore.getContractDataInBlock(blockNumber)));
|
|
278
|
-
}
|
|
279
|
-
|
|
280
274
|
/**
|
|
281
275
|
* Gets the number of the latest L2 block processed.
|
|
282
276
|
* @returns The number of the latest L2 block processed.
|
|
@@ -290,10 +284,11 @@ export class KVArchiverDataStore implements ArchiverDataStore {
|
|
|
290
284
|
*/
|
|
291
285
|
getL1BlockNumber(): Promise<ArchiverL1SynchPoint> {
|
|
292
286
|
const addedBlock = this.#blockStore.getL1BlockNumber();
|
|
293
|
-
const { addedMessages, cancelledMessages } = this.#messageStore.getL1BlockNumber();
|
|
287
|
+
const { addedMessages, cancelledMessages, newMessages } = this.#messageStore.getL1BlockNumber();
|
|
294
288
|
return Promise.resolve({
|
|
295
289
|
addedBlock,
|
|
296
290
|
addedMessages,
|
|
291
|
+
newMessages,
|
|
297
292
|
cancelledMessages,
|
|
298
293
|
});
|
|
299
294
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { L1ToL2Message } from '@aztec/circuit-types';
|
|
2
|
-
import { Fr } from '@aztec/circuits.js';
|
|
1
|
+
import { L1ToL2Message, NewInboxLeaf } from '@aztec/circuit-types';
|
|
2
|
+
import { Fr, L1_TO_L2_MSG_SUBTREE_HEIGHT } from '@aztec/circuits.js';
|
|
3
3
|
import { createDebugLogger } from '@aztec/foundation/log';
|
|
4
4
|
import { AztecCounter, AztecKVStore, AztecMap, AztecSingleton } from '@aztec/kv-store';
|
|
5
5
|
|
|
@@ -19,16 +19,23 @@ type Message = {
|
|
|
19
19
|
* LMDB implementation of the ArchiverDataStore interface.
|
|
20
20
|
*/
|
|
21
21
|
export class MessageStore {
|
|
22
|
-
#
|
|
22
|
+
#newMessages: AztecMap<string, Buffer>;
|
|
23
|
+
#lastL1BlockNewMessages: AztecSingleton<bigint>;
|
|
24
|
+
// TODO(#4492): Nuke the following when purging the old inbox
|
|
23
25
|
#pendingMessagesByFee: AztecCounter<[number, string]>;
|
|
26
|
+
#messages: AztecMap<string, Message>;
|
|
24
27
|
#lastL1BlockAddingMessages: AztecSingleton<bigint>;
|
|
25
28
|
#lastL1BlockCancellingMessages: AztecSingleton<bigint>;
|
|
26
29
|
|
|
27
30
|
#log = createDebugLogger('aztec:archiver:message_store');
|
|
28
31
|
|
|
32
|
+
#l1ToL2MessagesSubtreeSize = 2 ** L1_TO_L2_MSG_SUBTREE_HEIGHT;
|
|
33
|
+
|
|
29
34
|
constructor(private db: AztecKVStore) {
|
|
35
|
+
this.#newMessages = db.openMap('archiver_l1_to_l2_new_messages');
|
|
30
36
|
this.#messages = db.openMap('archiver_l1_to_l2_messages');
|
|
31
37
|
this.#pendingMessagesByFee = db.openCounter('archiver_messages_by_fee');
|
|
38
|
+
this.#lastL1BlockNewMessages = db.openSingleton('archiver_last_l1_block_new_messages');
|
|
32
39
|
this.#lastL1BlockAddingMessages = db.openSingleton('archiver_last_l1_block_adding_messages');
|
|
33
40
|
this.#lastL1BlockCancellingMessages = db.openSingleton('archiver_last_l1_block_cancelling_messages');
|
|
34
41
|
}
|
|
@@ -39,11 +46,40 @@ export class MessageStore {
|
|
|
39
46
|
*/
|
|
40
47
|
getL1BlockNumber() {
|
|
41
48
|
return {
|
|
49
|
+
newMessages: this.#lastL1BlockNewMessages.get() ?? 0n,
|
|
50
|
+
// TODO(#4492): Nuke the following when purging the old inbox
|
|
42
51
|
addedMessages: this.#lastL1BlockAddingMessages.get() ?? 0n,
|
|
43
52
|
cancelledMessages: this.#lastL1BlockCancellingMessages.get() ?? 0n,
|
|
44
53
|
};
|
|
45
54
|
}
|
|
46
55
|
|
|
56
|
+
/**
|
|
57
|
+
* Append new L1 to L2 messages to the store.
|
|
58
|
+
* @param messages - The L1 to L2 messages to be added to the store.
|
|
59
|
+
* @param lastMessageL1BlockNumber - The L1 block number in which the last message was emitted.
|
|
60
|
+
* @returns True if the operation is successful.
|
|
61
|
+
*/
|
|
62
|
+
addNewL1ToL2Messages(messages: NewInboxLeaf[], lastMessageL1BlockNumber: bigint): Promise<boolean> {
|
|
63
|
+
return this.db.transaction(() => {
|
|
64
|
+
const lastL1BlockNumber = this.#lastL1BlockNewMessages.get() ?? 0n;
|
|
65
|
+
if (lastL1BlockNumber >= lastMessageL1BlockNumber) {
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
void this.#lastL1BlockNewMessages.set(lastMessageL1BlockNumber);
|
|
70
|
+
|
|
71
|
+
for (const message of messages) {
|
|
72
|
+
if (message.index >= this.#l1ToL2MessagesSubtreeSize) {
|
|
73
|
+
throw new Error(`Message index ${message.index} out of subtree range`);
|
|
74
|
+
}
|
|
75
|
+
const key = `${message.blockNumber}-${message.index}`;
|
|
76
|
+
void this.#newMessages.setIfNotExists(key, message.leaf);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return true;
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
|
|
47
83
|
/**
|
|
48
84
|
* Append new pending L1 to L2 messages to the store.
|
|
49
85
|
* @param messages - The L1 to L2 messages to be added to the store.
|
|
@@ -171,4 +207,25 @@ export class MessageStore {
|
|
|
171
207
|
|
|
172
208
|
return entryKeys;
|
|
173
209
|
}
|
|
210
|
+
|
|
211
|
+
getNewL1ToL2Messages(blockNumber: bigint): Buffer[] {
|
|
212
|
+
const messages: Buffer[] = [];
|
|
213
|
+
let undefinedMessageFound = false;
|
|
214
|
+
for (let messageIndex = 0; messageIndex < this.#l1ToL2MessagesSubtreeSize; messageIndex++) {
|
|
215
|
+
// This is inefficient but probably fine for now.
|
|
216
|
+
const key = `${blockNumber}-${messageIndex}`;
|
|
217
|
+
const message = this.#newMessages.get(key);
|
|
218
|
+
if (message) {
|
|
219
|
+
if (undefinedMessageFound) {
|
|
220
|
+
throw new Error(`L1 to L2 message gap found in block ${blockNumber}`);
|
|
221
|
+
}
|
|
222
|
+
messages.push(message);
|
|
223
|
+
} else {
|
|
224
|
+
undefinedMessageFound = true;
|
|
225
|
+
// We continue iterating over messages here to verify that there are no more messages after the undefined one.
|
|
226
|
+
// --> If this was the case this would imply there is some issue with log fetching.
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
return messages;
|
|
230
|
+
}
|
|
174
231
|
}
|
|
@@ -1,6 +1,53 @@
|
|
|
1
|
-
import { L1ToL2Message } from '@aztec/circuit-types';
|
|
1
|
+
import { L1ToL2Message, NewInboxLeaf } from '@aztec/circuit-types';
|
|
2
|
+
import { L1_TO_L2_MSG_SUBTREE_HEIGHT } from '@aztec/circuits.js/constants';
|
|
2
3
|
import { Fr } from '@aztec/foundation/fields';
|
|
3
4
|
|
|
5
|
+
/**
|
|
6
|
+
* A simple in-memory implementation of an L1 to L2 message store
|
|
7
|
+
* that handles message duplication.
|
|
8
|
+
* TODO(#4492): Clean this up
|
|
9
|
+
*/
|
|
10
|
+
export class NewL1ToL2MessageStore {
|
|
11
|
+
/**
|
|
12
|
+
* A map containing the entry key to the corresponding L1 to L2
|
|
13
|
+
* messages (and the number of times the message has been seen).
|
|
14
|
+
*/
|
|
15
|
+
protected store: Map<string, Buffer> = new Map();
|
|
16
|
+
|
|
17
|
+
#l1ToL2MessagesSubtreeSize = 2 ** L1_TO_L2_MSG_SUBTREE_HEIGHT;
|
|
18
|
+
|
|
19
|
+
constructor() {}
|
|
20
|
+
|
|
21
|
+
addMessage(message: NewInboxLeaf) {
|
|
22
|
+
if (message.index >= this.#l1ToL2MessagesSubtreeSize) {
|
|
23
|
+
throw new Error(`Message index ${message.index} out of subtree range`);
|
|
24
|
+
}
|
|
25
|
+
const key = `${message.blockNumber}-${message.index}`;
|
|
26
|
+
this.store.set(key, message.leaf);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
getMessages(blockNumber: bigint): Buffer[] {
|
|
30
|
+
const messages: Buffer[] = [];
|
|
31
|
+
let undefinedMessageFound = false;
|
|
32
|
+
for (let messageIndex = 0; messageIndex < this.#l1ToL2MessagesSubtreeSize; messageIndex++) {
|
|
33
|
+
// This is inefficient but probably fine for now.
|
|
34
|
+
const key = `${blockNumber}-${messageIndex}`;
|
|
35
|
+
const message = this.store.get(key);
|
|
36
|
+
if (message) {
|
|
37
|
+
if (undefinedMessageFound) {
|
|
38
|
+
throw new Error(`L1 to L2 message gap found in block ${blockNumber}`);
|
|
39
|
+
}
|
|
40
|
+
messages.push(message);
|
|
41
|
+
} else {
|
|
42
|
+
undefinedMessageFound = true;
|
|
43
|
+
// We continue iterating over messages here to verify that there are no more messages after the undefined one.
|
|
44
|
+
// --> If this was the case this would imply there is some issue with log fetching.
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return messages;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
4
51
|
/**
|
|
5
52
|
* A simple in-memory implementation of an L1 to L2 message store
|
|
6
53
|
* that handles message duplication.
|