@aztec/archiver 0.0.0-test.1 → 0.0.1-commit.1142ef1

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.
Files changed (151) hide show
  1. package/README.md +27 -6
  2. package/dest/archiver/archiver.d.ts +204 -94
  3. package/dest/archiver/archiver.d.ts.map +1 -1
  4. package/dest/archiver/archiver.js +1616 -414
  5. package/dest/archiver/archiver_store.d.ts +178 -83
  6. package/dest/archiver/archiver_store.d.ts.map +1 -1
  7. package/dest/archiver/archiver_store_test_suite.d.ts +1 -1
  8. package/dest/archiver/archiver_store_test_suite.d.ts.map +1 -1
  9. package/dest/archiver/archiver_store_test_suite.js +2373 -397
  10. package/dest/archiver/config.d.ts +7 -22
  11. package/dest/archiver/config.d.ts.map +1 -1
  12. package/dest/archiver/config.js +30 -14
  13. package/dest/archiver/errors.d.ts +33 -1
  14. package/dest/archiver/errors.d.ts.map +1 -1
  15. package/dest/archiver/errors.js +49 -0
  16. package/dest/archiver/index.d.ts +3 -4
  17. package/dest/archiver/index.d.ts.map +1 -1
  18. package/dest/archiver/index.js +1 -2
  19. package/dest/archiver/instrumentation.d.ts +14 -6
  20. package/dest/archiver/instrumentation.d.ts.map +1 -1
  21. package/dest/archiver/instrumentation.js +45 -41
  22. package/dest/archiver/kv_archiver_store/block_store.d.ts +98 -21
  23. package/dest/archiver/kv_archiver_store/block_store.d.ts.map +1 -1
  24. package/dest/archiver/kv_archiver_store/block_store.js +495 -86
  25. package/dest/archiver/kv_archiver_store/contract_class_store.d.ts +4 -4
  26. package/dest/archiver/kv_archiver_store/contract_class_store.d.ts.map +1 -1
  27. package/dest/archiver/kv_archiver_store/contract_class_store.js +13 -19
  28. package/dest/archiver/kv_archiver_store/contract_instance_store.d.ts +12 -9
  29. package/dest/archiver/kv_archiver_store/contract_instance_store.d.ts.map +1 -1
  30. package/dest/archiver/kv_archiver_store/contract_instance_store.js +30 -16
  31. package/dest/archiver/kv_archiver_store/kv_archiver_store.d.ts +81 -75
  32. package/dest/archiver/kv_archiver_store/kv_archiver_store.d.ts.map +1 -1
  33. package/dest/archiver/kv_archiver_store/kv_archiver_store.js +145 -83
  34. package/dest/archiver/kv_archiver_store/log_store.d.ts +12 -16
  35. package/dest/archiver/kv_archiver_store/log_store.d.ts.map +1 -1
  36. package/dest/archiver/kv_archiver_store/log_store.js +151 -114
  37. package/dest/archiver/kv_archiver_store/message_store.d.ts +25 -18
  38. package/dest/archiver/kv_archiver_store/message_store.d.ts.map +1 -1
  39. package/dest/archiver/kv_archiver_store/message_store.js +152 -49
  40. package/dest/archiver/l1/bin/retrieve-calldata.d.ts +3 -0
  41. package/dest/archiver/l1/bin/retrieve-calldata.d.ts.map +1 -0
  42. package/dest/archiver/l1/bin/retrieve-calldata.js +149 -0
  43. package/dest/archiver/l1/calldata_retriever.d.ts +112 -0
  44. package/dest/archiver/l1/calldata_retriever.d.ts.map +1 -0
  45. package/dest/archiver/l1/calldata_retriever.js +471 -0
  46. package/dest/archiver/l1/data_retrieval.d.ts +90 -0
  47. package/dest/archiver/l1/data_retrieval.d.ts.map +1 -0
  48. package/dest/archiver/l1/data_retrieval.js +331 -0
  49. package/dest/archiver/l1/debug_tx.d.ts +19 -0
  50. package/dest/archiver/l1/debug_tx.d.ts.map +1 -0
  51. package/dest/archiver/l1/debug_tx.js +73 -0
  52. package/dest/archiver/l1/spire_proposer.d.ts +70 -0
  53. package/dest/archiver/l1/spire_proposer.d.ts.map +1 -0
  54. package/dest/archiver/l1/spire_proposer.js +157 -0
  55. package/dest/archiver/l1/trace_tx.d.ts +97 -0
  56. package/dest/archiver/l1/trace_tx.d.ts.map +1 -0
  57. package/dest/archiver/l1/trace_tx.js +91 -0
  58. package/dest/archiver/l1/types.d.ts +12 -0
  59. package/dest/archiver/l1/types.d.ts.map +1 -0
  60. package/dest/archiver/l1/types.js +3 -0
  61. package/dest/archiver/l1/validate_trace.d.ts +29 -0
  62. package/dest/archiver/l1/validate_trace.d.ts.map +1 -0
  63. package/dest/archiver/l1/validate_trace.js +150 -0
  64. package/dest/archiver/structs/data_retrieval.d.ts +1 -1
  65. package/dest/archiver/structs/inbox_message.d.ts +15 -0
  66. package/dest/archiver/structs/inbox_message.d.ts.map +1 -0
  67. package/dest/archiver/structs/inbox_message.js +39 -0
  68. package/dest/archiver/structs/published.d.ts +2 -11
  69. package/dest/archiver/structs/published.d.ts.map +1 -1
  70. package/dest/archiver/structs/published.js +1 -1
  71. package/dest/archiver/validation.d.ts +17 -0
  72. package/dest/archiver/validation.d.ts.map +1 -0
  73. package/dest/archiver/validation.js +98 -0
  74. package/dest/factory.d.ts +9 -14
  75. package/dest/factory.d.ts.map +1 -1
  76. package/dest/factory.js +22 -52
  77. package/dest/index.d.ts +2 -2
  78. package/dest/index.d.ts.map +1 -1
  79. package/dest/index.js +1 -1
  80. package/dest/rpc/index.d.ts +2 -3
  81. package/dest/rpc/index.d.ts.map +1 -1
  82. package/dest/rpc/index.js +1 -4
  83. package/dest/test/index.d.ts +1 -1
  84. package/dest/test/mock_archiver.d.ts +16 -8
  85. package/dest/test/mock_archiver.d.ts.map +1 -1
  86. package/dest/test/mock_archiver.js +19 -14
  87. package/dest/test/mock_l1_to_l2_message_source.d.ts +9 -6
  88. package/dest/test/mock_l1_to_l2_message_source.d.ts.map +1 -1
  89. package/dest/test/mock_l1_to_l2_message_source.js +30 -7
  90. package/dest/test/mock_l2_block_source.d.ts +56 -13
  91. package/dest/test/mock_l2_block_source.d.ts.map +1 -1
  92. package/dest/test/mock_l2_block_source.js +196 -25
  93. package/dest/test/mock_structs.d.ts +10 -0
  94. package/dest/test/mock_structs.d.ts.map +1 -0
  95. package/dest/test/mock_structs.js +38 -0
  96. package/package.json +29 -30
  97. package/src/archiver/archiver.ts +1596 -512
  98. package/src/archiver/archiver_store.ts +205 -88
  99. package/src/archiver/archiver_store_test_suite.ts +2386 -354
  100. package/src/archiver/config.ts +38 -46
  101. package/src/archiver/errors.ts +85 -0
  102. package/src/archiver/index.ts +2 -3
  103. package/src/archiver/instrumentation.ts +65 -45
  104. package/src/archiver/kv_archiver_store/block_store.ts +668 -101
  105. package/src/archiver/kv_archiver_store/contract_class_store.ts +14 -24
  106. package/src/archiver/kv_archiver_store/contract_instance_store.ts +36 -28
  107. package/src/archiver/kv_archiver_store/kv_archiver_store.ts +197 -113
  108. package/src/archiver/kv_archiver_store/log_store.ts +204 -132
  109. package/src/archiver/kv_archiver_store/message_store.ts +213 -54
  110. package/src/archiver/l1/README.md +98 -0
  111. package/src/archiver/l1/bin/retrieve-calldata.ts +182 -0
  112. package/src/archiver/l1/calldata_retriever.ts +641 -0
  113. package/src/archiver/l1/data_retrieval.ts +512 -0
  114. package/src/archiver/l1/debug_tx.ts +99 -0
  115. package/src/archiver/l1/spire_proposer.ts +160 -0
  116. package/src/archiver/l1/trace_tx.ts +128 -0
  117. package/src/archiver/l1/types.ts +13 -0
  118. package/src/archiver/l1/validate_trace.ts +211 -0
  119. package/src/archiver/structs/inbox_message.ts +41 -0
  120. package/src/archiver/structs/published.ts +1 -11
  121. package/src/archiver/validation.ts +124 -0
  122. package/src/factory.ts +28 -69
  123. package/src/index.ts +1 -1
  124. package/src/rpc/index.ts +1 -5
  125. package/src/test/fixtures/debug_traceTransaction-multicall3.json +88 -0
  126. package/src/test/fixtures/debug_traceTransaction-multiplePropose.json +153 -0
  127. package/src/test/fixtures/debug_traceTransaction-proxied.json +122 -0
  128. package/src/test/fixtures/trace_transaction-multicall3.json +65 -0
  129. package/src/test/fixtures/trace_transaction-multiplePropose.json +319 -0
  130. package/src/test/fixtures/trace_transaction-proxied.json +128 -0
  131. package/src/test/fixtures/trace_transaction-randomRevert.json +216 -0
  132. package/src/test/mock_archiver.ts +22 -16
  133. package/src/test/mock_l1_to_l2_message_source.ts +26 -8
  134. package/src/test/mock_l2_block_source.ts +254 -31
  135. package/src/test/mock_structs.ts +50 -0
  136. package/dest/archiver/data_retrieval.d.ts +0 -74
  137. package/dest/archiver/data_retrieval.d.ts.map +0 -1
  138. package/dest/archiver/data_retrieval.js +0 -283
  139. package/dest/archiver/kv_archiver_store/nullifier_store.d.ts +0 -12
  140. package/dest/archiver/kv_archiver_store/nullifier_store.d.ts.map +0 -1
  141. package/dest/archiver/kv_archiver_store/nullifier_store.js +0 -73
  142. package/dest/archiver/memory_archiver_store/l1_to_l2_message_store.d.ts +0 -23
  143. package/dest/archiver/memory_archiver_store/l1_to_l2_message_store.d.ts.map +0 -1
  144. package/dest/archiver/memory_archiver_store/l1_to_l2_message_store.js +0 -49
  145. package/dest/archiver/memory_archiver_store/memory_archiver_store.d.ts +0 -175
  146. package/dest/archiver/memory_archiver_store/memory_archiver_store.d.ts.map +0 -1
  147. package/dest/archiver/memory_archiver_store/memory_archiver_store.js +0 -636
  148. package/src/archiver/data_retrieval.ts +0 -422
  149. package/src/archiver/kv_archiver_store/nullifier_store.ts +0 -97
  150. package/src/archiver/memory_archiver_store/l1_to_l2_message_store.ts +0 -61
  151. package/src/archiver/memory_archiver_store/memory_archiver_store.ts +0 -801
@@ -1,422 +0,0 @@
1
- import { Blob, BlobDeserializationError } from '@aztec/blob-lib';
2
- import type { BlobSinkClientInterface } from '@aztec/blob-sink/client';
3
- import type { EpochProofPublicInputArgs, ViemPublicClient } from '@aztec/ethereum';
4
- import { asyncPool } from '@aztec/foundation/async-pool';
5
- import type { EthAddress } from '@aztec/foundation/eth-address';
6
- import type { ViemSignature } from '@aztec/foundation/eth-signature';
7
- import { Fr } from '@aztec/foundation/fields';
8
- import { type Logger, createLogger } from '@aztec/foundation/log';
9
- import { numToUInt32BE } from '@aztec/foundation/serialize';
10
- import { ForwarderAbi, type InboxAbi, RollupAbi } from '@aztec/l1-artifacts';
11
- import { Body, L2Block } from '@aztec/stdlib/block';
12
- import { InboxLeaf } from '@aztec/stdlib/messaging';
13
- import { Proof } from '@aztec/stdlib/proofs';
14
- import { AppendOnlyTreeSnapshot } from '@aztec/stdlib/trees';
15
- import { BlockHeader } from '@aztec/stdlib/tx';
16
-
17
- import {
18
- type GetContractEventsReturnType,
19
- type GetContractReturnType,
20
- type Hex,
21
- decodeFunctionData,
22
- getAbiItem,
23
- hexToBytes,
24
- } from 'viem';
25
-
26
- import { NoBlobBodiesFoundError } from './errors.js';
27
- import type { DataRetrieval } from './structs/data_retrieval.js';
28
- import type { L1Published, L1PublishedData } from './structs/published.js';
29
-
30
- /**
31
- * Fetches new L2 blocks.
32
- * @param publicClient - The viem public client to use for transaction retrieval.
33
- * @param rollupAddress - The address of the rollup contract.
34
- * @param searchStartBlock - The block number to use for starting the search.
35
- * @param searchEndBlock - The highest block number that we should search up to.
36
- * @param expectedNextL2BlockNum - The next L2 block number that we expect to find.
37
- * @returns An array of block; as well as the next eth block to search from.
38
- */
39
- export async function retrieveBlocksFromRollup(
40
- rollup: GetContractReturnType<typeof RollupAbi, ViemPublicClient>,
41
- publicClient: ViemPublicClient,
42
- blobSinkClient: BlobSinkClientInterface,
43
- searchStartBlock: bigint,
44
- searchEndBlock: bigint,
45
- logger: Logger = createLogger('archiver'),
46
- ): Promise<L1Published<L2Block>[]> {
47
- const retrievedBlocks: L1Published<L2Block>[] = [];
48
- do {
49
- if (searchStartBlock > searchEndBlock) {
50
- break;
51
- }
52
- const l2BlockProposedLogs = (
53
- await rollup.getEvents.L2BlockProposed(
54
- {},
55
- {
56
- fromBlock: searchStartBlock,
57
- toBlock: searchEndBlock,
58
- },
59
- )
60
- ).filter(log => log.blockNumber! >= searchStartBlock && log.blockNumber! <= searchEndBlock);
61
-
62
- if (l2BlockProposedLogs.length === 0) {
63
- break;
64
- }
65
-
66
- const lastLog = l2BlockProposedLogs[l2BlockProposedLogs.length - 1];
67
- logger.debug(
68
- `Got ${l2BlockProposedLogs.length} L2 block processed logs for L2 blocks ${l2BlockProposedLogs[0].args.blockNumber}-${lastLog.args.blockNumber} between L1 blocks ${searchStartBlock}-${searchEndBlock}`,
69
- );
70
-
71
- const newBlocks = await processL2BlockProposedLogs(
72
- rollup,
73
- publicClient,
74
- blobSinkClient,
75
- l2BlockProposedLogs,
76
- logger,
77
- );
78
- retrievedBlocks.push(...newBlocks);
79
- searchStartBlock = lastLog.blockNumber! + 1n;
80
- } while (searchStartBlock <= searchEndBlock);
81
-
82
- // The asyncpool from processL2BlockProposedLogs will not necessarily return the blocks in order, so we sort them before returning.
83
- return retrievedBlocks.sort((a, b) => Number(a.l1.blockNumber - b.l1.blockNumber));
84
- }
85
-
86
- /**
87
- * Processes newly received L2BlockProposed logs.
88
- * @param rollup - The rollup contract
89
- * @param publicClient - The viem public client to use for transaction retrieval.
90
- * @param logs - L2BlockProposed logs.
91
- * @returns - An array blocks.
92
- */
93
- export async function processL2BlockProposedLogs(
94
- rollup: GetContractReturnType<typeof RollupAbi, ViemPublicClient>,
95
- publicClient: ViemPublicClient,
96
- blobSinkClient: BlobSinkClientInterface,
97
- logs: GetContractEventsReturnType<typeof RollupAbi, 'L2BlockProposed'>,
98
- logger: Logger,
99
- ): Promise<L1Published<L2Block>[]> {
100
- const retrievedBlocks: L1Published<L2Block>[] = [];
101
- await asyncPool(10, logs, async log => {
102
- const l2BlockNumber = log.args.blockNumber!;
103
- const archive = log.args.archive!;
104
- const archiveFromChain = await rollup.read.archiveAt([l2BlockNumber]);
105
- const blobHashes = log.args.versionedBlobHashes!.map(blobHash => Buffer.from(blobHash.slice(2), 'hex'));
106
-
107
- // The value from the event and contract will match only if the block is in the chain.
108
- if (archive === archiveFromChain) {
109
- const block = await getBlockFromRollupTx(
110
- publicClient,
111
- blobSinkClient,
112
- log.transactionHash!,
113
- blobHashes,
114
- l2BlockNumber,
115
- rollup.address,
116
- logger,
117
- );
118
-
119
- const l1: L1PublishedData = {
120
- blockNumber: log.blockNumber,
121
- blockHash: log.blockHash,
122
- timestamp: await getL1BlockTime(publicClient, log.blockNumber),
123
- };
124
-
125
- retrievedBlocks.push({ data: block, l1 });
126
- } else {
127
- logger.warn(`Ignoring L2 block ${l2BlockNumber} due to archive root mismatch`, {
128
- actual: archive,
129
- expected: archiveFromChain,
130
- });
131
- }
132
- });
133
-
134
- return retrievedBlocks;
135
- }
136
-
137
- export async function getL1BlockTime(publicClient: ViemPublicClient, blockNumber: bigint): Promise<bigint> {
138
- const block = await publicClient.getBlock({ blockNumber, includeTransactions: false });
139
- return block.timestamp;
140
- }
141
-
142
- /**
143
- * Extracts the first 'propose' method calldata from a forwarder transaction's data.
144
- * @param forwarderData - The forwarder transaction input data
145
- * @param rollupAddress - The address of the rollup contract
146
- * @returns The calldata for the first 'propose' method call to the rollup contract
147
- */
148
- function extractRollupProposeCalldata(forwarderData: Hex, rollupAddress: Hex): Hex {
149
- // TODO(#11451): custom forwarders
150
- const { functionName: forwarderFunctionName, args: forwarderArgs } = decodeFunctionData({
151
- abi: ForwarderAbi,
152
- data: forwarderData,
153
- });
154
-
155
- if (forwarderFunctionName !== 'forward') {
156
- throw new Error(`Unexpected forwarder method called ${forwarderFunctionName}`);
157
- }
158
-
159
- if (forwarderArgs.length !== 2) {
160
- throw new Error(`Unexpected number of arguments for forwarder`);
161
- }
162
-
163
- const [to, data] = forwarderArgs;
164
-
165
- // Find all rollup calls
166
- const rollupAddressLower = rollupAddress.toLowerCase();
167
-
168
- for (let i = 0; i < to.length; i++) {
169
- const addr = to[i];
170
- if (addr.toLowerCase() !== rollupAddressLower) {
171
- continue;
172
- }
173
- const callData = data[i];
174
-
175
- try {
176
- const { functionName: rollupFunctionName } = decodeFunctionData({
177
- abi: RollupAbi,
178
- data: callData,
179
- });
180
-
181
- if (rollupFunctionName === 'propose') {
182
- return callData;
183
- }
184
- } catch (err) {
185
- // Skip invalid function data
186
- continue;
187
- }
188
- }
189
-
190
- throw new Error(`Rollup address not found in forwarder args`);
191
- }
192
-
193
- /**
194
- * Gets block from the calldata of an L1 transaction.
195
- * Assumes that the block was published from an EOA.
196
- * TODO: Add retries and error management.
197
- * @param publicClient - The viem public client to use for transaction retrieval.
198
- * @param txHash - Hash of the tx that published it.
199
- * @param l2BlockNum - L2 block number.
200
- * @returns L2 block from the calldata, deserialized
201
- */
202
- async function getBlockFromRollupTx(
203
- publicClient: ViemPublicClient,
204
- blobSinkClient: BlobSinkClientInterface,
205
- txHash: `0x${string}`,
206
- blobHashes: Buffer[], // WORKTODO(md): buffer32?
207
- l2BlockNum: bigint,
208
- rollupAddress: Hex,
209
- logger: Logger,
210
- ): Promise<L2Block> {
211
- const { input: forwarderData, blockHash } = await publicClient.getTransaction({ hash: txHash });
212
-
213
- const rollupData = extractRollupProposeCalldata(forwarderData, rollupAddress);
214
- const { functionName: rollupFunctionName, args: rollupArgs } = decodeFunctionData({
215
- abi: RollupAbi,
216
- data: rollupData,
217
- });
218
-
219
- if (rollupFunctionName !== 'propose') {
220
- throw new Error(`Unexpected rollup method called ${rollupFunctionName}`);
221
- }
222
-
223
- const [decodedArgs, ,] = rollupArgs! as readonly [
224
- {
225
- header: Hex;
226
- archive: Hex;
227
- blockHash: Hex;
228
- oracleInput: {
229
- feeAssetPriceModifier: bigint;
230
- };
231
- txHashes: Hex[];
232
- },
233
- ViemSignature[],
234
- Hex,
235
- ];
236
-
237
- const header = BlockHeader.fromBuffer(Buffer.from(hexToBytes(decodedArgs.header)));
238
- const blobBodies = await blobSinkClient.getBlobSidecar(blockHash, blobHashes);
239
- if (blobBodies.length === 0) {
240
- throw new NoBlobBodiesFoundError(Number(l2BlockNum));
241
- }
242
-
243
- let blockFields: Fr[];
244
- try {
245
- blockFields = Blob.toEncodedFields(blobBodies);
246
- } catch (err: any) {
247
- if (err instanceof BlobDeserializationError) {
248
- logger.fatal(err.message);
249
- } else {
250
- logger.fatal('Unable to sync: failed to decode fetched blob, this blob was likely not created by us');
251
- }
252
- throw err;
253
- }
254
-
255
- // The blob source gives us blockFields, and we must construct the body from them:
256
- const blockBody = Body.fromBlobFields(blockFields);
257
-
258
- const blockNumberFromHeader = header.globalVariables.blockNumber.toBigInt();
259
-
260
- if (blockNumberFromHeader !== l2BlockNum) {
261
- throw new Error(`Block number mismatch: expected ${l2BlockNum} but got ${blockNumberFromHeader}`);
262
- }
263
-
264
- const archive = AppendOnlyTreeSnapshot.fromBuffer(
265
- Buffer.concat([
266
- Buffer.from(hexToBytes(decodedArgs.archive)), // L2Block.archive.root
267
- numToUInt32BE(Number(l2BlockNum + 1n)), // L2Block.archive.nextAvailableLeafIndex
268
- ]),
269
- );
270
-
271
- return new L2Block(archive, header, blockBody);
272
- }
273
-
274
- /**
275
- * Fetch L1 to L2 messages.
276
- * @param publicClient - The viem public client to use for transaction retrieval.
277
- * @param inboxAddress - The address of the inbox contract to fetch messages from.
278
- * @param blockUntilSynced - If true, blocks until the archiver has fully synced.
279
- * @param searchStartBlock - The block number to use for starting the search.
280
- * @param searchEndBlock - The highest block number that we should search up to.
281
- * @returns An array of InboxLeaf and next eth block to search from.
282
- */
283
- export async function retrieveL1ToL2Messages(
284
- inbox: GetContractReturnType<typeof InboxAbi, ViemPublicClient>,
285
- searchStartBlock: bigint,
286
- searchEndBlock: bigint,
287
- ): Promise<DataRetrieval<InboxLeaf>> {
288
- const retrievedL1ToL2Messages: InboxLeaf[] = [];
289
- do {
290
- if (searchStartBlock > searchEndBlock) {
291
- break;
292
- }
293
-
294
- const messageSentLogs = (
295
- await inbox.getEvents.MessageSent(
296
- {},
297
- {
298
- fromBlock: searchStartBlock,
299
- toBlock: searchEndBlock,
300
- },
301
- )
302
- ).filter(log => log.blockNumber! >= searchStartBlock && log.blockNumber! <= searchEndBlock);
303
-
304
- if (messageSentLogs.length === 0) {
305
- break;
306
- }
307
-
308
- for (const log of messageSentLogs) {
309
- const { index, hash } = log.args;
310
- retrievedL1ToL2Messages.push(new InboxLeaf(index!, Fr.fromHexString(hash!)));
311
- }
312
-
313
- // handles the case when there are no new messages:
314
- searchStartBlock = (messageSentLogs.findLast(msgLog => !!msgLog)?.blockNumber || searchStartBlock) + 1n;
315
- } while (searchStartBlock <= searchEndBlock);
316
- return { lastProcessedL1BlockNumber: searchStartBlock - 1n, retrievedData: retrievedL1ToL2Messages };
317
- }
318
-
319
- /** Retrieves L2ProofVerified events from the rollup contract. */
320
- export async function retrieveL2ProofVerifiedEvents(
321
- publicClient: ViemPublicClient,
322
- rollupAddress: EthAddress,
323
- searchStartBlock: bigint,
324
- searchEndBlock?: bigint,
325
- ): Promise<{ l1BlockNumber: bigint; l2BlockNumber: bigint; proverId: Fr; txHash: Hex }[]> {
326
- const logs = await publicClient.getLogs({
327
- address: rollupAddress.toString(),
328
- fromBlock: searchStartBlock,
329
- toBlock: searchEndBlock ? searchEndBlock : undefined,
330
- strict: true,
331
- event: getAbiItem({ abi: RollupAbi, name: 'L2ProofVerified' }),
332
- });
333
-
334
- return logs.map(log => ({
335
- l1BlockNumber: log.blockNumber,
336
- l2BlockNumber: log.args.blockNumber,
337
- proverId: Fr.fromHexString(log.args.proverId),
338
- txHash: log.transactionHash,
339
- }));
340
- }
341
-
342
- /** Retrieve submitted proofs from the rollup contract */
343
- export async function retrieveL2ProofsFromRollup(
344
- publicClient: ViemPublicClient,
345
- rollupAddress: EthAddress,
346
- searchStartBlock: bigint,
347
- searchEndBlock?: bigint,
348
- ): Promise<DataRetrieval<{ proof: Proof; proverId: Fr; l2BlockNumber: bigint; txHash: `0x${string}` }>> {
349
- const logs = await retrieveL2ProofVerifiedEvents(publicClient, rollupAddress, searchStartBlock, searchEndBlock);
350
- const retrievedData: { proof: Proof; proverId: Fr; l2BlockNumber: bigint; txHash: `0x${string}` }[] = [];
351
- const lastProcessedL1BlockNumber = logs.length > 0 ? logs.at(-1)!.l1BlockNumber : searchStartBlock - 1n;
352
-
353
- for (const { txHash, proverId, l2BlockNumber } of logs) {
354
- const proofData = await getProofFromSubmitProofTx(publicClient, txHash, proverId);
355
- retrievedData.push({ proof: proofData.proof, proverId: proofData.proverId, l2BlockNumber, txHash });
356
- }
357
- return {
358
- retrievedData,
359
- lastProcessedL1BlockNumber,
360
- };
361
- }
362
-
363
- export type SubmitBlockProof = {
364
- archiveRoot: Fr;
365
- proverId: Fr;
366
- aggregationObject: Buffer;
367
- proof: Proof;
368
- };
369
-
370
- /**
371
- * Gets block metadata (header and archive snapshot) from the calldata of an L1 transaction.
372
- * Assumes that the block was published from an EOA.
373
- * TODO: Add retries and error management.
374
- * @param publicClient - The viem public client to use for transaction retrieval.
375
- * @param txHash - Hash of the tx that published it.
376
- * @param l2BlockNum - L2 block number.
377
- * @returns L2 block metadata (header and archive) from the calldata, deserialized
378
- */
379
- export async function getProofFromSubmitProofTx(
380
- publicClient: ViemPublicClient,
381
- txHash: `0x${string}`,
382
- expectedProverId: Fr,
383
- ): Promise<SubmitBlockProof> {
384
- const { input: data } = await publicClient.getTransaction({ hash: txHash });
385
- const { functionName, args } = decodeFunctionData({ abi: RollupAbi, data });
386
-
387
- let proverId: Fr;
388
- let archiveRoot: Fr;
389
- let aggregationObject: Buffer;
390
- let proof: Proof;
391
-
392
- if (functionName === 'submitEpochRootProof') {
393
- const [decodedArgs] = args as readonly [
394
- {
395
- start: bigint;
396
- end: bigint;
397
- args: EpochProofPublicInputArgs;
398
- fees: readonly Hex[];
399
- aggregationObject: Hex;
400
- proof: Hex;
401
- },
402
- ];
403
-
404
- aggregationObject = Buffer.from(hexToBytes(decodedArgs.aggregationObject));
405
- proverId = Fr.fromHexString(decodedArgs.args.proverId);
406
- archiveRoot = Fr.fromHexString(decodedArgs.args.endArchive);
407
- proof = Proof.fromBuffer(Buffer.from(hexToBytes(decodedArgs.proof)));
408
- } else {
409
- throw new Error(`Unexpected proof method called ${functionName}`);
410
- }
411
-
412
- if (!proverId.equals(expectedProverId)) {
413
- throw new Error(`Prover ID mismatch: expected ${expectedProverId} but got ${proverId}`);
414
- }
415
-
416
- return {
417
- proverId,
418
- aggregationObject,
419
- archiveRoot,
420
- proof,
421
- };
422
- }
@@ -1,97 +0,0 @@
1
- import { MAX_NULLIFIERS_PER_TX } from '@aztec/constants';
2
- import type { Fr } from '@aztec/foundation/fields';
3
- import { createLogger } from '@aztec/foundation/log';
4
- import type { AztecAsyncKVStore, AztecAsyncMap } from '@aztec/kv-store';
5
- import type { InBlock, L2Block } from '@aztec/stdlib/block';
6
-
7
- export class NullifierStore {
8
- #nullifiersToBlockNumber: AztecAsyncMap<string, number>;
9
- #nullifiersToBlockHash: AztecAsyncMap<string, string>;
10
- #nullifiersToIndex: AztecAsyncMap<string, number>;
11
- #log = createLogger('archiver:log_store');
12
-
13
- constructor(private db: AztecAsyncKVStore) {
14
- this.#nullifiersToBlockNumber = db.openMap('archiver_nullifiers_to_block_number');
15
- this.#nullifiersToBlockHash = db.openMap('archiver_nullifiers_to_block_hash');
16
- this.#nullifiersToIndex = db.openMap('archiver_nullifiers_to_index');
17
- }
18
-
19
- async addNullifiers(blocks: L2Block[]): Promise<boolean> {
20
- const blockHashes = await Promise.all(blocks.map(block => block.hash()));
21
- await this.db.transactionAsync(async () => {
22
- await Promise.all(
23
- blocks.map((block, i) => {
24
- const dataStartIndexForBlock =
25
- block.header.state.partial.nullifierTree.nextAvailableLeafIndex -
26
- block.body.txEffects.length * MAX_NULLIFIERS_PER_TX;
27
- return Promise.all(
28
- block.body.txEffects.map((txEffects, txIndex) => {
29
- const dataStartIndexForTx = dataStartIndexForBlock + txIndex * MAX_NULLIFIERS_PER_TX;
30
- return Promise.all(
31
- txEffects.nullifiers.map(async (nullifier, nullifierIndex) => {
32
- await this.#nullifiersToBlockNumber.set(nullifier.toString(), block.number);
33
- await this.#nullifiersToBlockHash.set(nullifier.toString(), blockHashes[i].toString());
34
- await this.#nullifiersToIndex.set(nullifier.toString(), dataStartIndexForTx + nullifierIndex);
35
- }),
36
- );
37
- }),
38
- );
39
- }),
40
- );
41
- });
42
- return true;
43
- }
44
-
45
- async deleteNullifiers(blocks: L2Block[]): Promise<boolean> {
46
- await this.db.transactionAsync(async () => {
47
- for (const block of blocks) {
48
- for (const nullifier of block.body.txEffects.flatMap(tx => tx.nullifiers)) {
49
- await Promise.all([
50
- this.#nullifiersToBlockNumber.delete(nullifier.toString()),
51
- this.#nullifiersToBlockHash.delete(nullifier.toString()),
52
- this.#nullifiersToIndex.delete(nullifier.toString()),
53
- ]);
54
- }
55
- }
56
- });
57
- return true;
58
- }
59
-
60
- async findNullifiersIndexesWithBlock(
61
- blockNumber: number,
62
- nullifiers: Fr[],
63
- ): Promise<(InBlock<bigint> | undefined)[]> {
64
- const asStrings = nullifiers.map(x => x.toString());
65
-
66
- const maybeNullifiers = await Promise.all(
67
- asStrings.map(async nullifier => {
68
- const [data, l2BlockNumber, l2BlockHash] = await Promise.all([
69
- this.#nullifiersToIndex.getAsync(nullifier),
70
- this.#nullifiersToBlockNumber.getAsync(nullifier),
71
- this.#nullifiersToBlockHash.getAsync(nullifier),
72
- ]);
73
- return {
74
- data,
75
- l2BlockNumber,
76
- l2BlockHash,
77
- };
78
- }),
79
- );
80
- return maybeNullifiers.map(({ data, l2BlockNumber, l2BlockHash }) => {
81
- if (
82
- data === undefined ||
83
- l2BlockNumber === undefined ||
84
- l2BlockHash === undefined ||
85
- l2BlockNumber > blockNumber
86
- ) {
87
- return undefined;
88
- } else {
89
- return {
90
- data: BigInt(data),
91
- l2BlockNumber,
92
- l2BlockHash,
93
- } as InBlock<bigint>;
94
- }
95
- });
96
- }
97
- }
@@ -1,61 +0,0 @@
1
- import { L1_TO_L2_MSG_SUBTREE_HEIGHT } from '@aztec/constants';
2
- import type { Fr } from '@aztec/foundation/fields';
3
- import { InboxLeaf } from '@aztec/stdlib/messaging';
4
-
5
- /**
6
- * A simple in-memory implementation of an L1 to L2 message store.
7
- */
8
- export class L1ToL2MessageStore {
9
- /**
10
- * A map pointing from a key in a "messageIndex" format to the corresponding L1 to L2 message hash.
11
- */
12
- protected store: Map<string, Fr> = new Map();
13
-
14
- #l1ToL2MessagesSubtreeSize = 2 ** L1_TO_L2_MSG_SUBTREE_HEIGHT;
15
-
16
- constructor() {}
17
-
18
- getTotalL1ToL2MessageCount(): bigint {
19
- return BigInt(this.store.size);
20
- }
21
-
22
- addMessage(message: InboxLeaf) {
23
- this.store.set(`${message.index}`, message.leaf);
24
- }
25
-
26
- getMessages(blockNumber: bigint): Fr[] {
27
- const messages: Fr[] = [];
28
- let undefinedMessageFound = false;
29
- const startIndex = Number(InboxLeaf.smallestIndexFromL2Block(blockNumber));
30
-
31
- for (let i = startIndex; i < startIndex + this.#l1ToL2MessagesSubtreeSize; i++) {
32
- // This is inefficient but probably fine for now.
33
- const message = this.store.get(`${i}`);
34
- if (message) {
35
- if (undefinedMessageFound) {
36
- throw new Error(`L1 to L2 message gap found in block ${blockNumber}`);
37
- }
38
- messages.push(message);
39
- } else {
40
- undefinedMessageFound = true;
41
- // We continue iterating over messages here to verify that there are no more messages after the undefined one.
42
- // --> If this was the case this would imply there is some issue with log fetching.
43
- }
44
- }
45
- return messages;
46
- }
47
-
48
- /**
49
- * Gets the L1 to L2 message index in the L1 to L2 message tree.
50
- * @param l1ToL2Message - The L1 to L2 message.
51
- * @returns The index of the L1 to L2 message in the L1 to L2 message tree (undefined if not found).
52
- */
53
- getMessageIndex(l1ToL2Message: Fr): bigint | undefined {
54
- for (const [key, message] of this.store.entries()) {
55
- if (message.equals(l1ToL2Message)) {
56
- return BigInt(key);
57
- }
58
- }
59
- return undefined;
60
- }
61
- }