@aztec-labs/prover-client 6.0.0-nightly.20260829

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 (170) hide show
  1. package/README.md +1 -0
  2. package/dest/config.d.ts +17 -0
  3. package/dest/config.d.ts.map +1 -0
  4. package/dest/config.js +63 -0
  5. package/dest/index.d.ts +4 -0
  6. package/dest/index.d.ts.map +1 -0
  7. package/dest/index.js +2 -0
  8. package/dest/light/index.d.ts +2 -0
  9. package/dest/light/index.d.ts.map +1 -0
  10. package/dest/light/index.js +1 -0
  11. package/dest/light/lightweight_checkpoint_builder.d.ts +58 -0
  12. package/dest/light/lightweight_checkpoint_builder.d.ts.map +1 -0
  13. package/dest/light/lightweight_checkpoint_builder.js +243 -0
  14. package/dest/mocks/fixtures.d.ts +20 -0
  15. package/dest/mocks/fixtures.d.ts.map +1 -0
  16. package/dest/mocks/fixtures.js +96 -0
  17. package/dest/mocks/test_context.d.ts +93 -0
  18. package/dest/mocks/test_context.d.ts.map +1 -0
  19. package/dest/mocks/test_context.js +354 -0
  20. package/dest/orchestrator/block-building-helpers.d.ts +67 -0
  21. package/dest/orchestrator/block-building-helpers.d.ts.map +1 -0
  22. package/dest/orchestrator/block-building-helpers.js +274 -0
  23. package/dest/orchestrator/block-proving-state.d.ts +107 -0
  24. package/dest/orchestrator/block-proving-state.d.ts.map +1 -0
  25. package/dest/orchestrator/block-proving-state.js +339 -0
  26. package/dest/orchestrator/checkpoint-proving-state.d.ts +67 -0
  27. package/dest/orchestrator/checkpoint-proving-state.d.ts.map +1 -0
  28. package/dest/orchestrator/checkpoint-proving-state.js +175 -0
  29. package/dest/orchestrator/checkpoint-sub-tree-orchestrator.d.ts +169 -0
  30. package/dest/orchestrator/checkpoint-sub-tree-orchestrator.d.ts.map +1 -0
  31. package/dest/orchestrator/checkpoint-sub-tree-orchestrator.js +1047 -0
  32. package/dest/orchestrator/chonk-cache.d.ts +39 -0
  33. package/dest/orchestrator/chonk-cache.d.ts.map +1 -0
  34. package/dest/orchestrator/chonk-cache.js +80 -0
  35. package/dest/orchestrator/index.d.ts +4 -0
  36. package/dest/orchestrator/index.d.ts.map +1 -0
  37. package/dest/orchestrator/index.js +3 -0
  38. package/dest/orchestrator/orchestrator_metrics.d.ts +8 -0
  39. package/dest/orchestrator/orchestrator_metrics.d.ts.map +1 -0
  40. package/dest/orchestrator/orchestrator_metrics.js +13 -0
  41. package/dest/orchestrator/proving-scheduler.d.ts +81 -0
  42. package/dest/orchestrator/proving-scheduler.d.ts.map +1 -0
  43. package/dest/orchestrator/proving-scheduler.js +120 -0
  44. package/dest/orchestrator/top-tree-orchestrator.d.ts +89 -0
  45. package/dest/orchestrator/top-tree-orchestrator.d.ts.map +1 -0
  46. package/dest/orchestrator/top-tree-orchestrator.js +233 -0
  47. package/dest/orchestrator/top-tree-proving-state.d.ts +61 -0
  48. package/dest/orchestrator/top-tree-proving-state.d.ts.map +1 -0
  49. package/dest/orchestrator/top-tree-proving-state.js +185 -0
  50. package/dest/orchestrator/tx-proving-state.d.ts +37 -0
  51. package/dest/orchestrator/tx-proving-state.d.ts.map +1 -0
  52. package/dest/orchestrator/tx-proving-state.js +77 -0
  53. package/dest/prover-client/factory.d.ts +6 -0
  54. package/dest/prover-client/factory.d.ts.map +1 -0
  55. package/dest/prover-client/factory.js +5 -0
  56. package/dest/prover-client/index.d.ts +3 -0
  57. package/dest/prover-client/index.d.ts.map +1 -0
  58. package/dest/prover-client/index.js +2 -0
  59. package/dest/prover-client/prover-client.d.ts +99 -0
  60. package/dest/prover-client/prover-client.d.ts.map +1 -0
  61. package/dest/prover-client/prover-client.js +163 -0
  62. package/dest/proving_broker/broker_prover_facade.d.ts +52 -0
  63. package/dest/proving_broker/broker_prover_facade.d.ts.map +1 -0
  64. package/dest/proving_broker/broker_prover_facade.js +360 -0
  65. package/dest/proving_broker/config.d.ts +40 -0
  66. package/dest/proving_broker/config.d.ts.map +1 -0
  67. package/dest/proving_broker/config.js +138 -0
  68. package/dest/proving_broker/factory.d.ts +5 -0
  69. package/dest/proving_broker/factory.d.ts.map +1 -0
  70. package/dest/proving_broker/factory.js +13 -0
  71. package/dest/proving_broker/fixtures.d.ts +6 -0
  72. package/dest/proving_broker/fixtures.d.ts.map +1 -0
  73. package/dest/proving_broker/fixtures.js +13 -0
  74. package/dest/proving_broker/index.d.ts +11 -0
  75. package/dest/proving_broker/index.d.ts.map +1 -0
  76. package/dest/proving_broker/index.js +10 -0
  77. package/dest/proving_broker/proof_store/factory.d.ts +3 -0
  78. package/dest/proving_broker/proof_store/factory.d.ts.map +1 -0
  79. package/dest/proving_broker/proof_store/factory.js +13 -0
  80. package/dest/proving_broker/proof_store/file_store_proof_store.d.ts +18 -0
  81. package/dest/proving_broker/proof_store/file_store_proof_store.d.ts.map +1 -0
  82. package/dest/proving_broker/proof_store/file_store_proof_store.js +60 -0
  83. package/dest/proving_broker/proof_store/index.d.ts +5 -0
  84. package/dest/proving_broker/proof_store/index.d.ts.map +1 -0
  85. package/dest/proving_broker/proof_store/index.js +4 -0
  86. package/dest/proving_broker/proof_store/inline_proof_store.d.ts +15 -0
  87. package/dest/proving_broker/proof_store/inline_proof_store.d.ts.map +1 -0
  88. package/dest/proving_broker/proof_store/inline_proof_store.js +41 -0
  89. package/dest/proving_broker/proof_store/proof_store.d.ts +36 -0
  90. package/dest/proving_broker/proof_store/proof_store.d.ts.map +1 -0
  91. package/dest/proving_broker/proof_store/proof_store.js +3 -0
  92. package/dest/proving_broker/proving_agent.d.ts +42 -0
  93. package/dest/proving_broker/proving_agent.d.ts.map +1 -0
  94. package/dest/proving_broker/proving_agent.js +155 -0
  95. package/dest/proving_broker/proving_broker.d.ts +77 -0
  96. package/dest/proving_broker/proving_broker.d.ts.map +1 -0
  97. package/dest/proving_broker/proving_broker.js +780 -0
  98. package/dest/proving_broker/proving_broker_database/memory.d.ts +20 -0
  99. package/dest/proving_broker/proving_broker_database/memory.d.ts.map +1 -0
  100. package/dest/proving_broker/proving_broker_database/memory.js +67 -0
  101. package/dest/proving_broker/proving_broker_database/persisted.d.ts +40 -0
  102. package/dest/proving_broker/proving_broker_database/persisted.d.ts.map +1 -0
  103. package/dest/proving_broker/proving_broker_database/persisted.js +623 -0
  104. package/dest/proving_broker/proving_broker_database.d.ts +66 -0
  105. package/dest/proving_broker/proving_broker_database.d.ts.map +1 -0
  106. package/dest/proving_broker/proving_broker_database.js +3 -0
  107. package/dest/proving_broker/proving_broker_instrumentation.d.ts +31 -0
  108. package/dest/proving_broker/proving_broker_instrumentation.d.ts.map +1 -0
  109. package/dest/proving_broker/proving_broker_instrumentation.js +97 -0
  110. package/dest/proving_broker/proving_job_controller.d.ts +34 -0
  111. package/dest/proving_broker/proving_job_controller.d.ts.map +1 -0
  112. package/dest/proving_broker/proving_job_controller.js +184 -0
  113. package/dest/proving_broker/rpc.d.ts +38 -0
  114. package/dest/proving_broker/rpc.d.ts.map +1 -0
  115. package/dest/proving_broker/rpc.js +138 -0
  116. package/dest/test/epoch_settlement.d.ts +36 -0
  117. package/dest/test/epoch_settlement.d.ts.map +1 -0
  118. package/dest/test/epoch_settlement.js +52 -0
  119. package/dest/test/index.d.ts +2 -0
  120. package/dest/test/index.d.ts.map +1 -0
  121. package/dest/test/index.js +1 -0
  122. package/dest/test/mock_proof_store.d.ts +9 -0
  123. package/dest/test/mock_proof_store.d.ts.map +1 -0
  124. package/dest/test/mock_proof_store.js +10 -0
  125. package/dest/test/mock_prover.d.ts +38 -0
  126. package/dest/test/mock_prover.d.ts.map +1 -0
  127. package/dest/test/mock_prover.js +91 -0
  128. package/package.json +113 -0
  129. package/src/config.ts +87 -0
  130. package/src/index.ts +4 -0
  131. package/src/light/index.ts +1 -0
  132. package/src/light/lightweight_checkpoint_builder.ts +342 -0
  133. package/src/mocks/fixtures.ts +120 -0
  134. package/src/mocks/test_context.ts +477 -0
  135. package/src/orchestrator/block-building-helpers.ts +486 -0
  136. package/src/orchestrator/block-proving-state.ts +457 -0
  137. package/src/orchestrator/checkpoint-proving-state.ts +247 -0
  138. package/src/orchestrator/checkpoint-sub-tree-orchestrator.ts +1010 -0
  139. package/src/orchestrator/chonk-cache.ts +99 -0
  140. package/src/orchestrator/index.ts +12 -0
  141. package/src/orchestrator/orchestrator_metrics.ts +18 -0
  142. package/src/orchestrator/proving-scheduler.ts +160 -0
  143. package/src/orchestrator/top-tree-orchestrator.ts +394 -0
  144. package/src/orchestrator/top-tree-proving-state.ts +219 -0
  145. package/src/orchestrator/tx-proving-state.ts +121 -0
  146. package/src/prover-client/factory.ts +18 -0
  147. package/src/prover-client/index.ts +2 -0
  148. package/src/prover-client/prover-client.ts +286 -0
  149. package/src/proving_broker/broker_prover_facade.ts +626 -0
  150. package/src/proving_broker/config.ts +178 -0
  151. package/src/proving_broker/factory.ts +19 -0
  152. package/src/proving_broker/fixtures.ts +20 -0
  153. package/src/proving_broker/index.ts +10 -0
  154. package/src/proving_broker/proof_store/factory.ts +20 -0
  155. package/src/proving_broker/proof_store/file_store_proof_store.ts +78 -0
  156. package/src/proving_broker/proof_store/index.ts +4 -0
  157. package/src/proving_broker/proof_store/inline_proof_store.ts +63 -0
  158. package/src/proving_broker/proof_store/proof_store.ts +54 -0
  159. package/src/proving_broker/proving_agent.ts +210 -0
  160. package/src/proving_broker/proving_broker.ts +888 -0
  161. package/src/proving_broker/proving_broker_database/memory.ts +78 -0
  162. package/src/proving_broker/proving_broker_database/persisted.ts +296 -0
  163. package/src/proving_broker/proving_broker_database.ts +75 -0
  164. package/src/proving_broker/proving_broker_instrumentation.ts +133 -0
  165. package/src/proving_broker/proving_job_controller.ts +199 -0
  166. package/src/proving_broker/rpc.ts +131 -0
  167. package/src/test/epoch_settlement.ts +82 -0
  168. package/src/test/index.ts +1 -0
  169. package/src/test/mock_proof_store.ts +14 -0
  170. package/src/test/mock_prover.ts +304 -0
@@ -0,0 +1,477 @@
1
+ import type { BBProverConfig } from '@aztec-labs/bb-prover';
2
+ import { TestCircuitProver } from '@aztec-labs/bb-prover';
3
+ import { BlockNumber, CheckpointNumber } from '@aztec-labs/foundation/branded-types';
4
+ import { times, timesAsync } from '@aztec-labs/foundation/collection';
5
+ import { Fr } from '@aztec-labs/foundation/curves/bn254';
6
+ import type { Logger } from '@aztec-labs/foundation/log';
7
+ import { SerialQueue } from '@aztec-labs/foundation/queue';
8
+ import type { FieldsOf } from '@aztec-labs/foundation/types';
9
+ import { getVKTreeRoot } from '@aztec-labs/noir-protocol-circuits-types/vk-tree';
10
+ import { ProtocolContractsList } from '@aztec-labs/protocol-contracts';
11
+ import { computeFeePayerBalanceLeafSlot } from '@aztec-labs/protocol-contracts/fee-juice';
12
+ import { PublicDataWrite } from '@aztec-labs/stdlib/avm';
13
+ import { AztecAddress } from '@aztec-labs/stdlib/aztec-address';
14
+ import type { Checkpoint } from '@aztec-labs/stdlib/checkpoint';
15
+ import type { MerkleTreeWriteOperations, ServerCircuitProver } from '@aztec-labs/stdlib/interfaces/server';
16
+ import type { CheckpointConstantData } from '@aztec-labs/stdlib/rollup';
17
+ import { mockProcessedTx } from '@aztec-labs/stdlib/testing';
18
+ import { MerkleTreeId, PublicDataTreeLeaf } from '@aztec-labs/stdlib/trees';
19
+ import {
20
+ type BlockHeader,
21
+ type GlobalVariables,
22
+ type ProcessedTx,
23
+ StateReference,
24
+ TreeSnapshots,
25
+ } from '@aztec-labs/stdlib/tx';
26
+ import type { GenesisData } from '@aztec-labs/stdlib/world-state';
27
+ import type { MerkleTreeAdminDatabase } from '@aztec-labs/world-state';
28
+ import { NativeWorldStateService } from '@aztec-labs/world-state/native';
29
+ import { promises as fs } from 'fs';
30
+
31
+ import { LightweightCheckpointBuilder } from '../light/lightweight_checkpoint_builder.js';
32
+ import {
33
+ buildFinalBlobChallenges,
34
+ getTreeSnapshot,
35
+ insertSideEffects,
36
+ } from '../orchestrator/block-building-helpers.js';
37
+ import { BrokerCircuitProverFacade } from '../proving_broker/broker_prover_facade.js';
38
+ import { TestBroker } from '../test/mock_prover.js';
39
+ import { getEnvironmentConfig, getSimulator, makeCheckpointConstants, makeGlobals } from './fixtures.js';
40
+
41
+ /**
42
+ * Builds a started `SerialQueue` for use as an orchestrator's deferred-job queue in
43
+ * tests. Production wires a single shared queue via `ProverClient`; tests that construct
44
+ * orchestrators directly use one of these per orchestrator (or share one).
45
+ */
46
+ export function makeTestDeferredJobQueue(concurrency = 10): SerialQueue {
47
+ const queue = new SerialQueue();
48
+ queue.start(concurrency);
49
+ return queue;
50
+ }
51
+
52
+ export class TestContext {
53
+ private headers: Map<number, BlockHeader> = new Map();
54
+ private checkpoints: Checkpoint[] = [];
55
+ private checkpointOutHashes: Fr[] = [];
56
+ private nextCheckpointIndex = 0;
57
+ private nextCheckpointNumber = CheckpointNumber(1);
58
+ private nextBlockNumber = 1;
59
+ private epochNumber = 1;
60
+ private feePayerBalance: Fr;
61
+ // Running inbox rolling hash across the checkpoints built by this context (never resets: the protocol threads it
62
+ // from genesis). Each checkpoint's builder starts from it, and it advances by the checkpoint's messages, so a
63
+ // checkpoint built after a message-carrying one commits the correct continuation in its header.
64
+ private currentInboxRollingHash = Fr.ZERO;
65
+
66
+ constructor(
67
+ public worldState: MerkleTreeAdminDatabase,
68
+ public prover: ServerCircuitProver,
69
+ public broker: TestBroker,
70
+ public brokerProverFacade: BrokerCircuitProverFacade,
71
+ private feePayer: AztecAddress,
72
+ initialFeePayerBalance: Fr,
73
+ private directoriesToCleanup: string[],
74
+ private logger: Logger,
75
+ ) {
76
+ this.feePayerBalance = initialFeePayerBalance;
77
+ }
78
+
79
+ static async new(
80
+ logger: Logger,
81
+ {
82
+ proverCount = 4,
83
+ createProver = async (bbConfig: BBProverConfig) => new TestCircuitProver(await getSimulator(bbConfig, logger)),
84
+ }: {
85
+ proverCount?: number;
86
+ createProver?: (bbConfig: BBProverConfig) => Promise<ServerCircuitProver>;
87
+ } = {},
88
+ ) {
89
+ const directoriesToCleanup: string[] = [];
90
+
91
+ const feePayer = AztecAddress.fromNumberUnsafe(42222);
92
+ const initialFeePayerBalance = new Fr(10n ** 20n);
93
+ const feePayerSlot = await computeFeePayerBalanceLeafSlot(feePayer);
94
+ const genesis: GenesisData = {
95
+ prefilledPublicData: [new PublicDataTreeLeaf(feePayerSlot, initialFeePayerBalance)],
96
+ genesisTimestamp: 0n,
97
+ };
98
+
99
+ // Separated dbs for public processor and prover - see public_processor for context
100
+ const ws = await NativeWorldStateService.tmp(/*cleanupTmpDir=*/ true, genesis);
101
+
102
+ let localProver: ServerCircuitProver;
103
+ const config = await getEnvironmentConfig(logger);
104
+ if (!config) {
105
+ localProver = new TestCircuitProver();
106
+ } else {
107
+ const bbConfig: BBProverConfig = {
108
+ acvmBinaryPath: config.expectedAcvmPath,
109
+ acvmWorkingDirectory: config.acvmWorkingDirectory,
110
+ bbBinaryPath: config.expectedBBPath,
111
+ bbWorkingDirectory: config.bbWorkingDirectory,
112
+ bbSkipCleanup: config.bbSkipCleanup,
113
+ numConcurrentIVCVerifiers: 8,
114
+ bbIVCConcurrency: 1,
115
+ bbChonkVerifyMaxBatch: 16,
116
+ bbChonkVerifyConcurrency: 6,
117
+ };
118
+ localProver = await createProver(bbConfig);
119
+ }
120
+
121
+ if (config?.directoryToCleanup && !config.bbSkipCleanup) {
122
+ directoriesToCleanup.push(config.directoryToCleanup);
123
+ }
124
+
125
+ const broker = new TestBroker(proverCount, localProver);
126
+ const facade = new BrokerCircuitProverFacade(broker);
127
+
128
+ await broker.start();
129
+ facade.start();
130
+
131
+ return new this(ws, localProver, broker, facade, feePayer, initialFeePayerBalance, directoriesToCleanup, logger);
132
+ }
133
+
134
+ public getFork() {
135
+ return this.worldState.fork();
136
+ }
137
+
138
+ async cleanup() {
139
+ await this.brokerProverFacade.stop();
140
+ await this.broker.stop();
141
+ await this.worldState.close();
142
+ for (const dir of this.directoriesToCleanup.filter(x => x !== '')) {
143
+ try {
144
+ await fs.rm(dir, { recursive: true, force: true, maxRetries: 3 });
145
+ } catch (err) {
146
+ this.logger.warn(`Failed to delete tmp directory $dir}: ${err}`);
147
+ }
148
+ }
149
+ }
150
+
151
+ public startNewEpoch() {
152
+ this.checkpoints = [];
153
+ this.checkpointOutHashes = [];
154
+ this.nextCheckpointIndex = 0;
155
+ this.epochNumber++;
156
+ }
157
+
158
+ // Return blob fields of all checkpoints in the epoch.
159
+ public getBlobFields() {
160
+ return this.checkpoints.map(checkpoint => checkpoint.toBlobFields());
161
+ }
162
+
163
+ public async getFinalBlobChallenges() {
164
+ const blobFields = this.getBlobFields();
165
+ return await buildFinalBlobChallenges(blobFields);
166
+ }
167
+
168
+ public async makeCheckpoint(
169
+ numBlocks: number,
170
+ {
171
+ numTxsPerBlock = 0,
172
+ numL1ToL2Messages = 0,
173
+ makeProcessedTxOpts = () => ({}),
174
+ ...constantOpts
175
+ }: {
176
+ numTxsPerBlock?: number | number[];
177
+ numL1ToL2Messages?: number;
178
+ makeProcessedTxOpts?: (
179
+ blockGlobalVariables: GlobalVariables,
180
+ txIndex: number,
181
+ ) => Partial<Parameters<typeof mockProcessedTx>[0]>;
182
+ } & Partial<FieldsOf<CheckpointConstantData>> = {},
183
+ ) {
184
+ if (numBlocks === 0) {
185
+ throw new Error(
186
+ 'Cannot make a checkpoint with 0 blocks. Crate an empty block (numTxsPerBlock = 0) if there are no txs.',
187
+ );
188
+ }
189
+
190
+ const checkpointIndex = this.nextCheckpointIndex++;
191
+ const checkpointNumber = this.nextCheckpointNumber;
192
+ this.nextCheckpointNumber++;
193
+ const slotNumber = checkpointNumber * 15; // times an arbitrary number to make it different to the checkpoint number
194
+
195
+ const constants = makeCheckpointConstants(slotNumber, constantOpts);
196
+
197
+ const fork = await this.worldState.fork();
198
+
199
+ // Build l1 to l2 messages. Appended unpadded at compact indices; the mock assigns them all to
200
+ // the checkpoint's first block, matching how the per-block driver slices them.
201
+ const l1ToL2Messages = times(numL1ToL2Messages, i => new Fr(slotNumber * 100 + i));
202
+ await fork.appendLeaves(MerkleTreeId.L1_TO_L2_MESSAGE_TREE, l1ToL2Messages);
203
+ const newL1ToL2Snapshot = await getTreeSnapshot(MerkleTreeId.L1_TO_L2_MESSAGE_TREE, fork);
204
+
205
+ const startBlockNumber = this.nextBlockNumber;
206
+ const previousBlockHeader = this.getBlockHeader(BlockNumber(startBlockNumber - 1));
207
+ // All blocks in the same slot/checkpoint share the same timestamp.
208
+ const timestamp = BigInt(slotNumber * 26);
209
+
210
+ // Build global variables.
211
+ const blockGlobalVariables = times(numBlocks, i =>
212
+ makeGlobals(startBlockNumber + i, slotNumber, {
213
+ coinbase: constants.coinbase,
214
+ feeRecipient: constants.feeRecipient,
215
+ gasFees: constants.gasFees,
216
+ timestamp,
217
+ }),
218
+ );
219
+ this.nextBlockNumber += numBlocks;
220
+
221
+ // Build txs.
222
+ let totalTxs = 0;
223
+ const blockEndStates: StateReference[] = [];
224
+ const blockTxs = await timesAsync(numBlocks, async blockIndex => {
225
+ const txIndexOffset = totalTxs;
226
+ const numTxs = typeof numTxsPerBlock === 'number' ? numTxsPerBlock : numTxsPerBlock[blockIndex];
227
+ totalTxs += numTxs;
228
+ const txs = await timesAsync(numTxs, txIndex =>
229
+ this.makeProcessedTx({
230
+ seed: (txIndexOffset + txIndex + 1) * 321 + (checkpointIndex + 1) * 123456 + this.epochNumber * 0x99999,
231
+ globalVariables: blockGlobalVariables[blockIndex],
232
+ anchorBlockHeader: previousBlockHeader,
233
+ newL1ToL2Snapshot,
234
+ ...makeProcessedTxOpts(blockGlobalVariables[blockIndex], txIndexOffset + txIndex),
235
+ }),
236
+ );
237
+
238
+ // Insert side effects into the trees.
239
+ const endState = await this.updateTrees(txs, fork);
240
+ blockEndStates.push(endState);
241
+
242
+ return txs;
243
+ });
244
+
245
+ const cleanFork = await this.worldState.fork();
246
+ const previousCheckpointOutHashes = this.checkpointOutHashes;
247
+ const startInboxRollingHash = this.currentInboxRollingHash;
248
+ const builder = LightweightCheckpointBuilder.startNewCheckpoint(
249
+ checkpointNumber,
250
+ { ...constants, timestamp },
251
+ previousCheckpointOutHashes,
252
+ startInboxRollingHash,
253
+ cleanFork,
254
+ );
255
+
256
+ // Add tx effects to db and build block headers.
257
+ const blocks = [];
258
+ for (let i = 0; i < numBlocks; i++) {
259
+ const txs = blockTxs[i];
260
+ const state = blockEndStates[i];
261
+
262
+ const { block } = await builder.addBlock(blockGlobalVariables[i], txs, i === 0 ? l1ToL2Messages : [], {
263
+ expectedEndState: state,
264
+ insertTxsEffects: true,
265
+ });
266
+
267
+ const header = block.header;
268
+ this.headers.set(block.number, header);
269
+
270
+ const blockMsgs = block.indexWithinCheckpoint === 0 ? l1ToL2Messages : [];
271
+ await this.worldState.handleL2BlockAndMessages(block, blockMsgs);
272
+
273
+ blocks.push({ header, txs });
274
+ }
275
+
276
+ const checkpoint = await builder.completeCheckpoint();
277
+ this.checkpoints.push(checkpoint);
278
+ this.checkpointOutHashes.push(checkpoint.getCheckpointOutHash());
279
+ this.currentInboxRollingHash = checkpoint.header.inboxRollingHash;
280
+
281
+ return {
282
+ constants,
283
+ checkpoint,
284
+ header: checkpoint.header,
285
+ blocks,
286
+ l1ToL2Messages,
287
+ previousBlockHeader,
288
+ startInboxRollingHash,
289
+ };
290
+ }
291
+
292
+ /**
293
+ * Like {@link makeCheckpoint} but distributes the L1-to-L2 message bundle across the checkpoint's blocks
294
+ * (streaming Inbox): `l1ToL2MessagesPerBlock[i]` is block `i`'s own message slice,
295
+ * appended at compact indices in insertion order. Lets tests exercise checkpoints whose messages span more
296
+ * than one block, including a non-first block carrying a bundle — the single-block-per-checkpoint
297
+ * `makeCheckpoint` puts every message in the first block. `numTxsPerBlock` defaults to 1 because the builder
298
+ * rejects a non-first block with neither txs nor messages; a zero-tx entry whose slice is non-empty is valid
299
+ * and produces a message-only block.
300
+ */
301
+ public async makeCheckpointWithMessagesPerBlock(
302
+ l1ToL2MessagesPerBlock: Fr[][],
303
+ {
304
+ numTxsPerBlock = 1,
305
+ makeProcessedTxOpts = () => ({}),
306
+ ...constantOpts
307
+ }: {
308
+ numTxsPerBlock?: number | number[];
309
+ makeProcessedTxOpts?: (
310
+ blockGlobalVariables: GlobalVariables,
311
+ txIndex: number,
312
+ ) => Partial<Parameters<typeof mockProcessedTx>[0]>;
313
+ } & Partial<FieldsOf<CheckpointConstantData>> = {},
314
+ ) {
315
+ const numBlocks = l1ToL2MessagesPerBlock.length;
316
+ if (numBlocks === 0) {
317
+ throw new Error('Cannot make a checkpoint with 0 blocks.');
318
+ }
319
+
320
+ const checkpointIndex = this.nextCheckpointIndex++;
321
+ const checkpointNumber = this.nextCheckpointNumber;
322
+ this.nextCheckpointNumber++;
323
+ const slotNumber = checkpointNumber * 15;
324
+
325
+ const constants = makeCheckpointConstants(slotNumber, constantOpts);
326
+ const l1ToL2Messages = l1ToL2MessagesPerBlock.flat();
327
+
328
+ const fork = await this.worldState.fork();
329
+
330
+ const startBlockNumber = this.nextBlockNumber;
331
+ const previousBlockHeader = this.getBlockHeader(BlockNumber(startBlockNumber - 1));
332
+ const timestamp = BigInt(slotNumber * 26);
333
+
334
+ const blockGlobalVariables = times(numBlocks, i =>
335
+ makeGlobals(startBlockNumber + i, slotNumber, {
336
+ coinbase: constants.coinbase,
337
+ feeRecipient: constants.feeRecipient,
338
+ gasFees: constants.gasFees,
339
+ timestamp,
340
+ }),
341
+ );
342
+ this.nextBlockNumber += numBlocks;
343
+
344
+ // Build txs per block. Append the block's message slice to the fork before its txs so the per-block end
345
+ // state matches the builder's (message-tree and tx-effect trees are independent, so append order does not
346
+ // matter, but the cumulative message tree must reflect the slices already inserted).
347
+ let totalTxs = 0;
348
+ const blockEndStates: StateReference[] = [];
349
+ const blockTxs = await timesAsync(numBlocks, async blockIndex => {
350
+ await fork.appendLeaves(MerkleTreeId.L1_TO_L2_MESSAGE_TREE, l1ToL2MessagesPerBlock[blockIndex]);
351
+ const newL1ToL2Snapshot = await getTreeSnapshot(MerkleTreeId.L1_TO_L2_MESSAGE_TREE, fork);
352
+
353
+ const txIndexOffset = totalTxs;
354
+ const numTxs = typeof numTxsPerBlock === 'number' ? numTxsPerBlock : numTxsPerBlock[blockIndex];
355
+ totalTxs += numTxs;
356
+ const txs = await timesAsync(numTxs, txIndex =>
357
+ this.makeProcessedTx({
358
+ seed: (txIndexOffset + txIndex + 1) * 321 + (checkpointIndex + 1) * 123456 + this.epochNumber * 0x99999,
359
+ globalVariables: blockGlobalVariables[blockIndex],
360
+ anchorBlockHeader: previousBlockHeader,
361
+ newL1ToL2Snapshot,
362
+ ...makeProcessedTxOpts(blockGlobalVariables[blockIndex], txIndexOffset + txIndex),
363
+ }),
364
+ );
365
+
366
+ const endState = await this.updateTrees(txs, fork);
367
+ blockEndStates.push(endState);
368
+
369
+ return txs;
370
+ });
371
+
372
+ const cleanFork = await this.worldState.fork();
373
+ const previousCheckpointOutHashes = this.checkpointOutHashes;
374
+ const startInboxRollingHash = this.currentInboxRollingHash;
375
+ const builder = LightweightCheckpointBuilder.startNewCheckpoint(
376
+ checkpointNumber,
377
+ { ...constants, timestamp },
378
+ previousCheckpointOutHashes,
379
+ startInboxRollingHash,
380
+ cleanFork,
381
+ );
382
+
383
+ const blocks = [];
384
+ for (let i = 0; i < numBlocks; i++) {
385
+ const txs = blockTxs[i];
386
+ const state = blockEndStates[i];
387
+
388
+ const { block } = await builder.addBlock(blockGlobalVariables[i], txs, l1ToL2MessagesPerBlock[i], {
389
+ expectedEndState: state,
390
+ insertTxsEffects: true,
391
+ });
392
+
393
+ const header = block.header;
394
+ this.headers.set(block.number, header);
395
+
396
+ await this.worldState.handleL2BlockAndMessages(block, l1ToL2MessagesPerBlock[i]);
397
+
398
+ blocks.push({ header, txs });
399
+ }
400
+
401
+ const checkpoint = await builder.completeCheckpoint();
402
+ this.checkpoints.push(checkpoint);
403
+ this.checkpointOutHashes.push(checkpoint.getCheckpointOutHash());
404
+ this.currentInboxRollingHash = checkpoint.header.inboxRollingHash;
405
+
406
+ return {
407
+ constants,
408
+ checkpoint,
409
+ header: checkpoint.header,
410
+ blocks,
411
+ l1ToL2Messages,
412
+ l1ToL2MessagesPerBlock,
413
+ previousBlockHeader,
414
+ startInboxRollingHash,
415
+ };
416
+ }
417
+
418
+ private async makeProcessedTx(opts: Parameters<typeof mockProcessedTx>[0] = {}): Promise<ProcessedTx> {
419
+ const tx = await mockProcessedTx({
420
+ vkTreeRoot: getVKTreeRoot(),
421
+ protocolContracts: ProtocolContractsList,
422
+ feePayer: this.feePayer,
423
+ ...opts,
424
+ });
425
+
426
+ this.feePayerBalance = new Fr(this.feePayerBalance.toBigInt() - tx.txEffect.transactionFee.toBigInt());
427
+
428
+ const feePayerSlot = await computeFeePayerBalanceLeafSlot(this.feePayer);
429
+ const feePaymentPublicDataWrite = new PublicDataWrite(feePayerSlot, this.feePayerBalance);
430
+ tx.txEffect.publicDataWrites[0] = feePaymentPublicDataWrite;
431
+ if (tx.avmProvingRequest) {
432
+ tx.avmProvingRequest.inputs.publicInputs.accumulatedData.publicDataWrites[0] = feePaymentPublicDataWrite;
433
+ }
434
+
435
+ return tx;
436
+ }
437
+
438
+ private getBlockHeader(blockNumber: BlockNumber): BlockHeader {
439
+ if (Number(blockNumber) > 0 && Number(blockNumber) >= this.nextBlockNumber) {
440
+ throw new Error(`Block header not built for block number ${blockNumber}.`);
441
+ }
442
+ return Number(blockNumber) === 0
443
+ ? this.worldState.getCommitted().getInitialHeader()
444
+ : this.headers.get(Number(blockNumber))!;
445
+ }
446
+
447
+ private async updateTrees(txs: ProcessedTx[], fork: MerkleTreeWriteOperations) {
448
+ let startStateReference = await fork.getStateReference();
449
+ let endStateReference = startStateReference;
450
+ for (const tx of txs) {
451
+ await insertSideEffects(tx, fork);
452
+ endStateReference = await fork.getStateReference();
453
+
454
+ if (tx.avmProvingRequest) {
455
+ // Update the trees in the avm public inputs so that the proof won't fail.
456
+ const l1ToL2MessageTree = tx.avmProvingRequest.inputs.publicInputs.startTreeSnapshots.l1ToL2MessageTree;
457
+ tx.avmProvingRequest.inputs.publicInputs.startTreeSnapshots = new TreeSnapshots(
458
+ l1ToL2MessageTree,
459
+ startStateReference.partial.noteHashTree,
460
+ startStateReference.partial.nullifierTree,
461
+ startStateReference.partial.publicDataTree,
462
+ );
463
+
464
+ tx.avmProvingRequest.inputs.publicInputs.endTreeSnapshots = new TreeSnapshots(
465
+ l1ToL2MessageTree,
466
+ endStateReference.partial.noteHashTree,
467
+ endStateReference.partial.nullifierTree,
468
+ endStateReference.partial.publicDataTree,
469
+ );
470
+ }
471
+
472
+ startStateReference = endStateReference;
473
+ }
474
+
475
+ return endStateReference;
476
+ }
477
+ }