@aztec/prover-client 0.0.1-commit.03f7ef2 → 0.0.1-commit.04d373f

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 (150) hide show
  1. package/dest/config.d.ts +1 -1
  2. package/dest/config.d.ts.map +1 -1
  3. package/dest/config.js +16 -2
  4. package/dest/light/lightweight_checkpoint_builder.d.ts +22 -6
  5. package/dest/light/lightweight_checkpoint_builder.d.ts.map +1 -1
  6. package/dest/light/lightweight_checkpoint_builder.js +112 -28
  7. package/dest/mocks/fixtures.d.ts +1 -1
  8. package/dest/mocks/fixtures.d.ts.map +1 -1
  9. package/dest/mocks/fixtures.js +2 -1
  10. package/dest/mocks/test_context.d.ts +6 -2
  11. package/dest/mocks/test_context.d.ts.map +1 -1
  12. package/dest/mocks/test_context.js +31 -11
  13. package/dest/orchestrator/block-building-helpers.d.ts +5 -5
  14. package/dest/orchestrator/block-building-helpers.d.ts.map +1 -1
  15. package/dest/orchestrator/block-building-helpers.js +4 -4
  16. package/dest/orchestrator/block-proving-state.d.ts +4 -1
  17. package/dest/orchestrator/block-proving-state.d.ts.map +1 -1
  18. package/dest/orchestrator/block-proving-state.js +7 -0
  19. package/dest/orchestrator/checkpoint-proving-state.d.ts +24 -4
  20. package/dest/orchestrator/checkpoint-proving-state.d.ts.map +1 -1
  21. package/dest/orchestrator/checkpoint-proving-state.js +47 -5
  22. package/dest/orchestrator/checkpoint-sub-tree-orchestrator.d.ts +107 -0
  23. package/dest/orchestrator/checkpoint-sub-tree-orchestrator.d.ts.map +1 -0
  24. package/dest/orchestrator/checkpoint-sub-tree-orchestrator.js +151 -0
  25. package/dest/orchestrator/epoch-proving-context.d.ts +51 -0
  26. package/dest/orchestrator/epoch-proving-context.d.ts.map +1 -0
  27. package/dest/orchestrator/epoch-proving-context.js +81 -0
  28. package/dest/orchestrator/epoch-proving-state.d.ts +7 -6
  29. package/dest/orchestrator/epoch-proving-state.d.ts.map +1 -1
  30. package/dest/orchestrator/epoch-proving-state.js +37 -1
  31. package/dest/orchestrator/index.d.ts +4 -1
  32. package/dest/orchestrator/index.d.ts.map +1 -1
  33. package/dest/orchestrator/index.js +3 -0
  34. package/dest/orchestrator/orchestrator.d.ts +30 -25
  35. package/dest/orchestrator/orchestrator.d.ts.map +1 -1
  36. package/dest/orchestrator/orchestrator.js +549 -255
  37. package/dest/orchestrator/orchestrator_metrics.d.ts +1 -1
  38. package/dest/orchestrator/orchestrator_metrics.d.ts.map +1 -1
  39. package/dest/orchestrator/orchestrator_metrics.js +2 -6
  40. package/dest/orchestrator/proving-scheduler.d.ts +72 -0
  41. package/dest/orchestrator/proving-scheduler.d.ts.map +1 -0
  42. package/dest/orchestrator/proving-scheduler.js +117 -0
  43. package/dest/orchestrator/top-tree-orchestrator.d.ts +83 -0
  44. package/dest/orchestrator/top-tree-orchestrator.d.ts.map +1 -0
  45. package/dest/orchestrator/top-tree-orchestrator.js +182 -0
  46. package/dest/orchestrator/top-tree-proving-scheduler.d.ts +62 -0
  47. package/dest/orchestrator/top-tree-proving-scheduler.d.ts.map +1 -0
  48. package/dest/orchestrator/top-tree-proving-scheduler.js +73 -0
  49. package/dest/orchestrator/top-tree-proving-state.d.ts +61 -0
  50. package/dest/orchestrator/top-tree-proving-state.d.ts.map +1 -0
  51. package/dest/orchestrator/top-tree-proving-state.js +185 -0
  52. package/dest/orchestrator/tx-proving-state.d.ts +5 -4
  53. package/dest/orchestrator/tx-proving-state.d.ts.map +1 -1
  54. package/dest/orchestrator/tx-proving-state.js +6 -6
  55. package/dest/prover-client/factory.d.ts +3 -3
  56. package/dest/prover-client/factory.d.ts.map +1 -1
  57. package/dest/prover-client/prover-client.d.ts +66 -7
  58. package/dest/prover-client/prover-client.d.ts.map +1 -1
  59. package/dest/prover-client/prover-client.js +64 -11
  60. package/dest/proving_broker/broker_prover_facade.d.ts +7 -5
  61. package/dest/proving_broker/broker_prover_facade.d.ts.map +1 -1
  62. package/dest/proving_broker/broker_prover_facade.js +16 -22
  63. package/dest/proving_broker/config.d.ts +12 -64
  64. package/dest/proving_broker/config.d.ts.map +1 -1
  65. package/dest/proving_broker/config.js +22 -5
  66. package/dest/proving_broker/index.d.ts +2 -1
  67. package/dest/proving_broker/index.d.ts.map +1 -1
  68. package/dest/proving_broker/index.js +1 -0
  69. package/dest/proving_broker/proof_store/factory.d.ts +2 -5
  70. package/dest/proving_broker/proof_store/factory.d.ts.map +1 -1
  71. package/dest/proving_broker/proof_store/factory.js +7 -30
  72. package/dest/proving_broker/proof_store/file_store_proof_store.d.ts +18 -0
  73. package/dest/proving_broker/proof_store/file_store_proof_store.d.ts.map +1 -0
  74. package/dest/proving_broker/proof_store/file_store_proof_store.js +60 -0
  75. package/dest/proving_broker/proof_store/index.d.ts +2 -2
  76. package/dest/proving_broker/proof_store/index.d.ts.map +1 -1
  77. package/dest/proving_broker/proof_store/index.js +1 -1
  78. package/dest/proving_broker/proving_agent.d.ts +5 -9
  79. package/dest/proving_broker/proving_agent.d.ts.map +1 -1
  80. package/dest/proving_broker/proving_agent.js +4 -19
  81. package/dest/proving_broker/proving_broker.d.ts +8 -5
  82. package/dest/proving_broker/proving_broker.d.ts.map +1 -1
  83. package/dest/proving_broker/proving_broker.js +69 -21
  84. package/dest/proving_broker/proving_broker_database/persisted.d.ts +3 -2
  85. package/dest/proving_broker/proving_broker_database/persisted.d.ts.map +1 -1
  86. package/dest/proving_broker/proving_broker_database/persisted.js +391 -3
  87. package/dest/proving_broker/proving_broker_instrumentation.d.ts +3 -1
  88. package/dest/proving_broker/proving_broker_instrumentation.d.ts.map +1 -1
  89. package/dest/proving_broker/proving_broker_instrumentation.js +22 -35
  90. package/dest/proving_broker/proving_job_controller.d.ts +4 -3
  91. package/dest/proving_broker/proving_job_controller.d.ts.map +1 -1
  92. package/dest/proving_broker/proving_job_controller.js +6 -3
  93. package/dest/proving_broker/rpc.d.ts +6 -2
  94. package/dest/proving_broker/rpc.d.ts.map +1 -1
  95. package/dest/proving_broker/rpc.js +87 -23
  96. package/dest/test/mock_proof_store.d.ts +3 -3
  97. package/dest/test/mock_proof_store.d.ts.map +1 -1
  98. package/dest/test/mock_prover.d.ts +5 -5
  99. package/dest/test/mock_prover.d.ts.map +1 -1
  100. package/dest/test/mock_prover.js +3 -3
  101. package/package.json +19 -21
  102. package/src/config.ts +18 -2
  103. package/src/light/lightweight_checkpoint_builder.ts +159 -37
  104. package/src/mocks/fixtures.ts +2 -1
  105. package/src/mocks/test_context.ts +24 -11
  106. package/src/orchestrator/block-building-helpers.ts +4 -4
  107. package/src/orchestrator/block-proving-state.ts +9 -0
  108. package/src/orchestrator/checkpoint-proving-state.ts +65 -6
  109. package/src/orchestrator/checkpoint-sub-tree-orchestrator.ts +271 -0
  110. package/src/orchestrator/epoch-proving-context.ts +101 -0
  111. package/src/orchestrator/epoch-proving-state.ts +59 -9
  112. package/src/orchestrator/index.ts +8 -0
  113. package/src/orchestrator/orchestrator.ts +165 -293
  114. package/src/orchestrator/orchestrator_metrics.ts +2 -6
  115. package/src/orchestrator/proving-scheduler.ts +156 -0
  116. package/src/orchestrator/top-tree-orchestrator.ts +314 -0
  117. package/src/orchestrator/top-tree-proving-scheduler.ts +154 -0
  118. package/src/orchestrator/top-tree-proving-state.ts +220 -0
  119. package/src/orchestrator/tx-proving-state.ts +8 -11
  120. package/src/prover-client/factory.ts +6 -2
  121. package/src/prover-client/prover-client.ts +157 -24
  122. package/src/proving_broker/broker_prover_facade.ts +25 -26
  123. package/src/proving_broker/config.ts +25 -2
  124. package/src/proving_broker/index.ts +1 -0
  125. package/src/proving_broker/proof_store/factory.ts +10 -32
  126. package/src/proving_broker/proof_store/file_store_proof_store.ts +78 -0
  127. package/src/proving_broker/proof_store/index.ts +1 -1
  128. package/src/proving_broker/proving_agent.ts +6 -19
  129. package/src/proving_broker/proving_broker.ts +65 -16
  130. package/src/proving_broker/proving_broker_database/persisted.ts +17 -3
  131. package/src/proving_broker/proving_broker_instrumentation.ts +23 -35
  132. package/src/proving_broker/proving_job_controller.ts +9 -3
  133. package/src/proving_broker/rpc.ts +46 -20
  134. package/src/test/mock_prover.ts +1 -8
  135. package/dest/block-factory/index.d.ts +0 -2
  136. package/dest/block-factory/index.d.ts.map +0 -1
  137. package/dest/block-factory/index.js +0 -1
  138. package/dest/block-factory/light.d.ts +0 -38
  139. package/dest/block-factory/light.d.ts.map +0 -1
  140. package/dest/block-factory/light.js +0 -108
  141. package/dest/proving_broker/proof_store/gcs_proof_store.d.ts +0 -14
  142. package/dest/proving_broker/proof_store/gcs_proof_store.d.ts.map +0 -1
  143. package/dest/proving_broker/proof_store/gcs_proof_store.js +0 -52
  144. package/dest/proving_broker/proving_agent_instrumentation.d.ts +0 -8
  145. package/dest/proving_broker/proving_agent_instrumentation.d.ts.map +0 -1
  146. package/dest/proving_broker/proving_agent_instrumentation.js +0 -16
  147. package/src/block-factory/index.ts +0 -1
  148. package/src/block-factory/light.ts +0 -137
  149. package/src/proving_broker/proof_store/gcs_proof_store.ts +0 -76
  150. package/src/proving_broker/proving_agent_instrumentation.ts +0 -21
@@ -1,18 +1,21 @@
1
1
  import { SpongeBlob, computeBlobsHashFromBlobs, encodeCheckpointEndMarker, getBlobsPerL1Block } from '@aztec/blob-lib';
2
- import { NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP } from '@aztec/constants';
3
- import type { CheckpointNumber } from '@aztec/foundation/branded-types';
4
- import { padArrayEnd } from '@aztec/foundation/collection';
2
+ import { type CheckpointNumber, IndexWithinCheckpoint } from '@aztec/foundation/branded-types';
5
3
  import { Fr } from '@aztec/foundation/curves/bn254';
6
- import { createLogger } from '@aztec/foundation/log';
7
- import { L2BlockNew } from '@aztec/stdlib/block';
4
+ import { type Logger, type LoggerBindings, createLogger } from '@aztec/foundation/log';
5
+ import { elapsed } from '@aztec/foundation/timer';
6
+ import { L2Block } from '@aztec/stdlib/block';
8
7
  import { Checkpoint } from '@aztec/stdlib/checkpoint';
9
8
  import type { MerkleTreeWriteOperations } from '@aztec/stdlib/interfaces/server';
10
- import { computeCheckpointOutHash, computeInHashFromL1ToL2Messages } from '@aztec/stdlib/messaging';
9
+ import {
10
+ accumulateCheckpointOutHashes,
11
+ appendL1ToL2MessagesToTree,
12
+ computeCheckpointOutHash,
13
+ computeInHashFromL1ToL2Messages,
14
+ } from '@aztec/stdlib/messaging';
11
15
  import { CheckpointHeader, computeBlockHeadersHash } from '@aztec/stdlib/rollup';
12
16
  import { AppendOnlyTreeSnapshot, MerkleTreeId } from '@aztec/stdlib/trees';
13
17
  import {
14
18
  type CheckpointGlobalVariables,
15
- ContentCommitment,
16
19
  type GlobalVariables,
17
20
  type ProcessedTx,
18
21
  StateReference,
@@ -31,36 +34,128 @@ import {
31
34
  * Finally completes the checkpoint by computing its header.
32
35
  */
33
36
  export class LightweightCheckpointBuilder {
34
- private readonly logger = createLogger('lightweight-checkpoint-builder');
37
+ private readonly logger: Logger;
35
38
 
36
39
  private lastArchives: AppendOnlyTreeSnapshot[] = [];
37
40
  private spongeBlob: SpongeBlob;
38
- private blocks: L2BlockNew[] = [];
41
+ private blocks: L2Block[] = [];
39
42
  private blobFields: Fr[] = [];
40
43
 
41
44
  constructor(
42
45
  public readonly checkpointNumber: CheckpointNumber,
43
46
  public readonly constants: CheckpointGlobalVariables,
47
+ public feeAssetPriceModifier: bigint,
44
48
  public readonly l1ToL2Messages: Fr[],
49
+ private readonly previousCheckpointOutHashes: Fr[],
45
50
  public readonly db: MerkleTreeWriteOperations,
51
+ bindings?: LoggerBindings,
46
52
  ) {
53
+ this.logger = createLogger('checkpoint-builder', {
54
+ ...bindings,
55
+ instanceId: `checkpoint-${checkpointNumber}`,
56
+ });
47
57
  this.spongeBlob = SpongeBlob.init();
48
- this.logger.debug('Starting new checkpoint', { constants, l1ToL2Messages });
58
+ this.logger.debug('Starting new checkpoint', { constants, l1ToL2Messages, feeAssetPriceModifier });
49
59
  }
50
60
 
51
61
  static async startNewCheckpoint(
52
62
  checkpointNumber: CheckpointNumber,
53
63
  constants: CheckpointGlobalVariables,
54
64
  l1ToL2Messages: Fr[],
65
+ previousCheckpointOutHashes: Fr[],
55
66
  db: MerkleTreeWriteOperations,
67
+ bindings?: LoggerBindings,
68
+ feeAssetPriceModifier: bigint = 0n,
56
69
  ): Promise<LightweightCheckpointBuilder> {
57
70
  // Insert l1-to-l2 messages into the tree.
58
- await db.appendLeaves(
59
- MerkleTreeId.L1_TO_L2_MESSAGE_TREE,
60
- padArrayEnd<Fr, number>(l1ToL2Messages, Fr.ZERO, NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP),
71
+ await appendL1ToL2MessagesToTree(db, l1ToL2Messages);
72
+
73
+ return new LightweightCheckpointBuilder(
74
+ checkpointNumber,
75
+ constants,
76
+ feeAssetPriceModifier,
77
+ l1ToL2Messages,
78
+ previousCheckpointOutHashes,
79
+ db,
80
+ bindings,
81
+ );
82
+ }
83
+
84
+ /**
85
+ * Resumes building a checkpoint from existing blocks. This is used for validator re-execution
86
+ * where blocks have already been built and their effects are already in the database.
87
+ * Unlike startNewCheckpoint, this does NOT append l1ToL2Messages to the tree since they
88
+ * were already added when the blocks were originally built.
89
+ */
90
+ static async resumeCheckpoint(
91
+ checkpointNumber: CheckpointNumber,
92
+ constants: CheckpointGlobalVariables,
93
+ feeAssetPriceModifier: bigint,
94
+ l1ToL2Messages: Fr[],
95
+ previousCheckpointOutHashes: Fr[],
96
+ db: MerkleTreeWriteOperations,
97
+ existingBlocks: L2Block[],
98
+ bindings?: LoggerBindings,
99
+ ): Promise<LightweightCheckpointBuilder> {
100
+ const builder = new LightweightCheckpointBuilder(
101
+ checkpointNumber,
102
+ constants,
103
+ feeAssetPriceModifier,
104
+ l1ToL2Messages,
105
+ previousCheckpointOutHashes,
106
+ db,
107
+ bindings,
61
108
  );
62
109
 
63
- return new LightweightCheckpointBuilder(checkpointNumber, constants, l1ToL2Messages, db);
110
+ builder.logger.debug('Resuming checkpoint from existing blocks', {
111
+ checkpointNumber,
112
+ numExistingBlocks: existingBlocks.length,
113
+ blockNumbers: existingBlocks.map(b => b.header.getBlockNumber()),
114
+ });
115
+
116
+ if (existingBlocks.length === 0) {
117
+ throw new Error(`Cannot resume checkpoint ${checkpointNumber} with no existing blocks`);
118
+ }
119
+
120
+ // Validate block order and consistency
121
+ for (let i = 1; i < existingBlocks.length; i++) {
122
+ const prev = existingBlocks[i - 1];
123
+ const curr = existingBlocks[i];
124
+ if (curr.number !== prev.number + 1) {
125
+ throw new Error(`Non-sequential block numbers in resumeCheckpoint: ${prev.number} -> ${curr.number}`);
126
+ }
127
+ if (!prev.archive.root.equals(curr.header.lastArchive.root)) {
128
+ throw new Error(`Archive root mismatch between blocks ${prev.number} and ${curr.number}`);
129
+ }
130
+ }
131
+
132
+ for (let i = 0; i < existingBlocks.length; i++) {
133
+ const block = existingBlocks[i];
134
+ const isFirstBlock = i === 0;
135
+
136
+ if (isFirstBlock) {
137
+ builder.lastArchives.push(block.header.lastArchive);
138
+ }
139
+
140
+ builder.lastArchives.push(block.archive);
141
+
142
+ const blockBlobFields = block.toBlobFields();
143
+ await builder.spongeBlob.absorb(blockBlobFields);
144
+ builder.blobFields.push(...blockBlobFields);
145
+
146
+ builder.blocks.push(block);
147
+ }
148
+
149
+ return builder;
150
+ }
151
+
152
+ /** Returns how many blocks have been added to this checkpoint so far */
153
+ public getBlockCount() {
154
+ return this.blocks.length;
155
+ }
156
+
157
+ public getBlocks() {
158
+ return this.blocks;
64
159
  }
65
160
 
66
161
  /**
@@ -71,7 +166,8 @@ export class LightweightCheckpointBuilder {
71
166
  globalVariables: GlobalVariables,
72
167
  txs: ProcessedTx[],
73
168
  opts: { insertTxsEffects?: boolean; expectedEndState?: StateReference } = {},
74
- ): Promise<L2BlockNew> {
169
+ ): Promise<{ block: L2Block; timings: Record<string, number> }> {
170
+ const timings: Record<string, number> = {};
75
171
  const isFirstBlock = this.blocks.length === 0;
76
172
 
77
173
  // Empty blocks are only allowed as the first block in a checkpoint
@@ -80,7 +176,9 @@ export class LightweightCheckpointBuilder {
80
176
  }
81
177
 
82
178
  if (isFirstBlock) {
83
- this.lastArchives.push(await getTreeSnapshot(MerkleTreeId.ARCHIVE, this.db));
179
+ const [msGetInitialArchive, initialArchive] = await elapsed(() => getTreeSnapshot(MerkleTreeId.ARCHIVE, this.db));
180
+ this.lastArchives.push(initialArchive);
181
+ timings.getInitialArchive = msGetInitialArchive;
84
182
  }
85
183
 
86
184
  const lastArchive = this.lastArchives.at(-1)!;
@@ -90,12 +188,17 @@ export class LightweightCheckpointBuilder {
90
188
  `Inserting side effects for ${txs.length} txs for block ${globalVariables.blockNumber} into db`,
91
189
  { txs: txs.map(tx => tx.hash.toString()) },
92
190
  );
191
+ let msInsertSideEffects = 0;
93
192
  for (const tx of txs) {
94
- await insertSideEffects(tx, this.db);
193
+ const [ms] = await elapsed(() => insertSideEffects(tx, this.db));
194
+ msInsertSideEffects += ms;
95
195
  }
196
+ timings.insertSideEffects = msInsertSideEffects;
96
197
  }
97
198
 
98
- const endState = await this.db.getStateReference();
199
+ const [msGetEndState, endState] = await elapsed(() => this.db.getStateReference());
200
+ timings.getEndState = msGetEndState;
201
+
99
202
  if (opts.expectedEndState && !endState.equals(opts.expectedEndState)) {
100
203
  this.logger.error('End state after processing txs does not match expected end state', {
101
204
  globalVariables: globalVariables.toInspect(),
@@ -105,26 +208,31 @@ export class LightweightCheckpointBuilder {
105
208
  throw new Error(`End state does not match expected end state when building block ${globalVariables.blockNumber}`);
106
209
  }
107
210
 
108
- const { header, body, blockBlobFields } = await buildHeaderAndBodyFromTxs(
109
- txs,
110
- lastArchive,
111
- endState,
112
- globalVariables,
113
- this.spongeBlob,
114
- isFirstBlock,
211
+ const [msBuildHeaderAndBody, { header, body, blockBlobFields }] = await elapsed(() =>
212
+ buildHeaderAndBodyFromTxs(txs, lastArchive, endState, globalVariables, this.spongeBlob, isFirstBlock),
115
213
  );
214
+ timings.buildHeaderAndBody = msBuildHeaderAndBody;
116
215
 
117
216
  header.state.validate();
118
217
 
119
218
  await this.db.updateArchive(header);
120
- const newArchive = await getTreeSnapshot(MerkleTreeId.ARCHIVE, this.db);
219
+ const [msUpdateArchive, newArchive] = await elapsed(() => getTreeSnapshot(MerkleTreeId.ARCHIVE, this.db));
220
+ timings.updateArchive = msUpdateArchive;
121
221
  this.lastArchives.push(newArchive);
122
222
 
123
- const indexWithinCheckpoint = this.blocks.length;
124
- const block = new L2BlockNew(newArchive, header, body, this.checkpointNumber, indexWithinCheckpoint);
223
+ const expectedNextLeafIndex = Number(globalVariables.blockNumber) + 1;
224
+ if (newArchive.nextAvailableLeafIndex !== expectedNextLeafIndex) {
225
+ throw new Error(
226
+ `Archive tree next leaf index mismatch after building block ${globalVariables.blockNumber} (expected ${expectedNextLeafIndex} but got ${newArchive.nextAvailableLeafIndex})`,
227
+ );
228
+ }
229
+
230
+ const indexWithinCheckpoint = IndexWithinCheckpoint(this.blocks.length);
231
+ const block = new L2Block(newArchive, header, body, this.checkpointNumber, indexWithinCheckpoint);
125
232
  this.blocks.push(block);
126
233
 
127
- await this.spongeBlob.absorb(blockBlobFields);
234
+ const [msSpongeAbsorb] = await elapsed(() => this.spongeBlob.absorb(blockBlobFields));
235
+ timings.spongeAbsorb = msSpongeAbsorb;
128
236
  this.blobFields.push(...blockBlobFields);
129
237
 
130
238
  this.logger.debug(`Built block ${header.getBlockNumber()}`, {
@@ -135,7 +243,7 @@ export class LightweightCheckpointBuilder {
135
243
  txs: block.body.txEffects.map(tx => tx.txHash.toString()),
136
244
  });
137
245
 
138
- return block;
246
+ return { block, timings };
139
247
  }
140
248
 
141
249
  async completeCheckpoint(): Promise<Checkpoint> {
@@ -152,24 +260,27 @@ export class LightweightCheckpointBuilder {
152
260
 
153
261
  const newArchive = this.lastArchives[this.lastArchives.length - 1];
154
262
 
155
- const blobs = getBlobsPerL1Block(this.blobFields);
263
+ const blobs = await getBlobsPerL1Block(this.blobFields);
156
264
  const blobsHash = computeBlobsHashFromBlobs(blobs);
157
265
 
158
266
  const inHash = computeInHashFromL1ToL2Messages(this.l1ToL2Messages);
159
267
 
160
- const outHash = computeCheckpointOutHash(blocks.map(block => block.body.txEffects.map(tx => tx.l2ToL1Msgs)));
161
-
162
268
  const { slotNumber, coinbase, feeRecipient, gasFees } = this.constants;
269
+ const checkpointOutHash = computeCheckpointOutHash(
270
+ blocks.map(block => block.body.txEffects.map(tx => tx.l2ToL1Msgs)),
271
+ );
272
+ const epochOutHash = accumulateCheckpointOutHashes([...this.previousCheckpointOutHashes, checkpointOutHash]);
163
273
 
164
- // TODO(palla/mbps): Should we source this from the constants instead?
165
- // timestamp of a checkpoint is the timestamp of the last block in the checkpoint.
274
+ // All blocks in the checkpoint have the same timestamp
166
275
  const timestamp = blocks[blocks.length - 1].timestamp;
167
276
 
168
277
  const totalManaUsed = blocks.reduce((acc, block) => acc.add(block.header.totalManaUsed), Fr.ZERO);
169
278
 
170
279
  const header = CheckpointHeader.from({
171
280
  lastArchiveRoot: this.lastArchives[0].root,
172
- contentCommitment: new ContentCommitment(blobsHash, inHash, outHash),
281
+ blobsHash,
282
+ inHash,
283
+ epochOutHash,
173
284
  blockHeadersHash,
174
285
  slotNumber,
175
286
  timestamp,
@@ -179,15 +290,26 @@ export class LightweightCheckpointBuilder {
179
290
  totalManaUsed,
180
291
  });
181
292
 
182
- return new Checkpoint(newArchive, header, blocks, this.checkpointNumber);
293
+ this.logger.debug(`Completed checkpoint ${this.checkpointNumber}`, {
294
+ checkpointNumber: this.checkpointNumber,
295
+ headerHash: header.hash().toString(),
296
+ checkpointOutHash: checkpointOutHash.toString(),
297
+ numPreviousCheckpointOutHashes: this.previousCheckpointOutHashes.length,
298
+ ...header.toInspect(),
299
+ });
300
+
301
+ return new Checkpoint(newArchive, header, blocks, this.checkpointNumber, this.feeAssetPriceModifier);
183
302
  }
184
303
 
185
304
  clone() {
186
305
  const clone = new LightweightCheckpointBuilder(
187
306
  this.checkpointNumber,
188
307
  this.constants,
308
+ this.feeAssetPriceModifier,
189
309
  [...this.l1ToL2Messages],
310
+ [...this.previousCheckpointOutHashes],
190
311
  this.db,
312
+ this.logger.getBindings(),
191
313
  );
192
314
  clone.lastArchives = [...this.lastArchives];
193
315
  clone.spongeBlob = this.spongeBlob.clone();
@@ -75,7 +75,8 @@ export async function getSimulator(
75
75
  logger?.info(
76
76
  `Using native ACVM at ${config.acvmBinaryPath} and working directory ${config.acvmWorkingDirectory}`,
77
77
  );
78
- return new NativeACVMSimulator(config.acvmWorkingDirectory, config.acvmBinaryPath);
78
+ const acvmLogger = logger?.createChild('acvm-native');
79
+ return new NativeACVMSimulator(config.acvmWorkingDirectory, config.acvmBinaryPath, undefined, acvmLogger);
79
80
  } catch {
80
81
  logger?.warn(`Failed to access ACVM at ${config.acvmBinaryPath}, falling back to WASM`);
81
82
  }
@@ -24,6 +24,7 @@ import {
24
24
  StateReference,
25
25
  TreeSnapshots,
26
26
  } from '@aztec/stdlib/tx';
27
+ import type { GenesisData } from '@aztec/stdlib/world-state';
27
28
  import type { MerkleTreeAdminDatabase } from '@aztec/world-state';
28
29
  import { NativeWorldStateService } from '@aztec/world-state/native';
29
30
 
@@ -44,7 +45,9 @@ import { getEnvironmentConfig, getSimulator, makeCheckpointConstants, makeGlobal
44
45
  export class TestContext {
45
46
  private headers: Map<number, BlockHeader> = new Map();
46
47
  private checkpoints: Checkpoint[] = [];
48
+ private checkpointOutHashes: Fr[] = [];
47
49
  private nextCheckpointIndex = 0;
50
+ private nextCheckpointNumber = CheckpointNumber(1);
48
51
  private nextBlockNumber = 1;
49
52
  private epochNumber = 1;
50
53
  private feePayerBalance: Fr;
@@ -82,14 +85,13 @@ export class TestContext {
82
85
  const feePayer = AztecAddress.fromNumber(42222);
83
86
  const initialFeePayerBalance = new Fr(10n ** 20n);
84
87
  const feePayerSlot = await computeFeePayerBalanceLeafSlot(feePayer);
85
- const prefilledPublicData = [new PublicDataTreeLeaf(feePayerSlot, initialFeePayerBalance)];
88
+ const genesis: GenesisData = {
89
+ prefilledPublicData: [new PublicDataTreeLeaf(feePayerSlot, initialFeePayerBalance)],
90
+ genesisTimestamp: 0n,
91
+ };
86
92
 
87
93
  // Separated dbs for public processor and prover - see public_processor for context
88
- const ws = await NativeWorldStateService.tmp(
89
- /*rollupAddress=*/ undefined,
90
- /*cleanupTmpDir=*/ true,
91
- prefilledPublicData,
92
- );
94
+ const ws = await NativeWorldStateService.tmp(/*rollupAddress=*/ undefined, /*cleanupTmpDir=*/ true, genesis);
93
95
 
94
96
  let localProver: ServerCircuitProver;
95
97
  const config = await getEnvironmentConfig(logger);
@@ -102,8 +104,10 @@ export class TestContext {
102
104
  bbBinaryPath: config.expectedBBPath,
103
105
  bbWorkingDirectory: config.bbWorkingDirectory,
104
106
  bbSkipCleanup: config.bbSkipCleanup,
105
- numConcurrentIVCVerifiers: 2,
107
+ numConcurrentIVCVerifiers: 8,
106
108
  bbIVCConcurrency: 1,
109
+ bbChonkVerifyMaxBatch: 16,
110
+ bbChonkVerifyConcurrency: 6,
107
111
  };
108
112
  localProver = await createProver(bbConfig);
109
113
  }
@@ -114,7 +118,7 @@ export class TestContext {
114
118
 
115
119
  const broker = new TestBroker(proverCount, localProver);
116
120
  const facade = new BrokerCircuitProverFacade(broker);
117
- const orchestrator = new TestProvingOrchestrator(ws, facade, EthAddress.ZERO);
121
+ const orchestrator = new TestProvingOrchestrator(ws, facade, EthAddress.ZERO, false, 10);
118
122
 
119
123
  await broker.start();
120
124
  facade.start();
@@ -150,6 +154,7 @@ export class TestContext {
150
154
 
151
155
  public startNewEpoch() {
152
156
  this.checkpoints = [];
157
+ this.checkpointOutHashes = [];
153
158
  this.nextCheckpointIndex = 0;
154
159
  this.epochNumber++;
155
160
  }
@@ -187,7 +192,8 @@ export class TestContext {
187
192
  }
188
193
 
189
194
  const checkpointIndex = this.nextCheckpointIndex++;
190
- const checkpointNumber = CheckpointNumber(checkpointIndex + 1);
195
+ const checkpointNumber = this.nextCheckpointNumber;
196
+ this.nextCheckpointNumber++;
191
197
  const slotNumber = checkpointNumber * 15; // times an arbitrary number to make it different to the checkpoint number
192
198
 
193
199
  const constants = makeCheckpointConstants(slotNumber, constantOpts);
@@ -204,6 +210,8 @@ export class TestContext {
204
210
 
205
211
  const startBlockNumber = this.nextBlockNumber;
206
212
  const previousBlockHeader = this.getBlockHeader(BlockNumber(startBlockNumber - 1));
213
+ // All blocks in the same slot/checkpoint share the same timestamp.
214
+ const timestamp = BigInt(slotNumber * 26);
207
215
 
208
216
  // Build global variables.
209
217
  const blockGlobalVariables = times(numBlocks, i =>
@@ -211,6 +219,7 @@ export class TestContext {
211
219
  coinbase: constants.coinbase,
212
220
  feeRecipient: constants.feeRecipient,
213
221
  gasFees: constants.gasFees,
222
+ timestamp,
214
223
  }),
215
224
  );
216
225
  this.nextBlockNumber += numBlocks;
@@ -240,10 +249,12 @@ export class TestContext {
240
249
  });
241
250
 
242
251
  const cleanFork = await this.worldState.fork();
252
+ const previousCheckpointOutHashes = this.checkpointOutHashes;
243
253
  const builder = await LightweightCheckpointBuilder.startNewCheckpoint(
244
254
  checkpointNumber,
245
- constants,
255
+ { ...constants, timestamp },
246
256
  l1ToL2Messages,
257
+ previousCheckpointOutHashes,
247
258
  cleanFork,
248
259
  );
249
260
 
@@ -253,7 +264,7 @@ export class TestContext {
253
264
  const txs = blockTxs[i];
254
265
  const state = blockEndStates[i];
255
266
 
256
- const block = await builder.addBlock(blockGlobalVariables[i], txs, {
267
+ const { block } = await builder.addBlock(blockGlobalVariables[i], txs, {
257
268
  expectedEndState: state,
258
269
  insertTxsEffects: true,
259
270
  });
@@ -269,9 +280,11 @@ export class TestContext {
269
280
 
270
281
  const checkpoint = await builder.completeCheckpoint();
271
282
  this.checkpoints.push(checkpoint);
283
+ this.checkpointOutHashes.push(checkpoint.getCheckpointOutHash());
272
284
 
273
285
  return {
274
286
  constants,
287
+ checkpoint,
275
288
  header: checkpoint.header,
276
289
  blocks,
277
290
  l1ToL2Messages,
@@ -99,7 +99,7 @@ export const insertSideEffectsAndBuildBaseRollupHints = runInSpan(
99
99
 
100
100
  const blockHash = await tx.data.constants.anchorBlockHeader.hash();
101
101
  const anchorBlockArchiveSiblingPath = (
102
- await getMembershipWitnessFor(blockHash, MerkleTreeId.ARCHIVE, ARCHIVE_HEIGHT, db)
102
+ await getMembershipWitnessFor(blockHash.toFr(), MerkleTreeId.ARCHIVE, ARCHIVE_HEIGHT, db)
103
103
  ).siblingPath;
104
104
 
105
105
  const contractClassLogsFields = makeTuple(
@@ -253,8 +253,8 @@ export function getPublicChonkVerifierPrivateInputsFromTx(tx: Tx | ProcessedTx,
253
253
  // Build "hints" as the private inputs for the checkpoint root rollup circuit.
254
254
  // The `blobCommitments` will be accumulated and checked in the root rollup against the `finalBlobChallenges`.
255
255
  // The `blobsHash` will be validated on L1 against the submitted blob data.
256
- export const buildBlobHints = (blobFields: Fr[]) => {
257
- const blobs = getBlobsPerL1Block(blobFields);
256
+ export const buildBlobHints = async (blobFields: Fr[]) => {
257
+ const blobs = await getBlobsPerL1Block(blobFields);
258
258
  const blobCommitments = getBlobCommitmentsFromBlobs(blobs);
259
259
  const blobsHash = computeBlobsHashFromBlobs(blobs);
260
260
  return { blobCommitments, blobs, blobsHash };
@@ -282,7 +282,7 @@ export const buildHeaderFromCircuitOutputs = runInSpan(
282
282
  chainId: constants.chainId,
283
283
  version: constants.version,
284
284
  blockNumber: BlockNumber(blockRootRollupOutput.previousArchive.nextAvailableLeafIndex),
285
- timestamp: blockRootRollupOutput.endTimestamp,
285
+ timestamp: blockRootRollupOutput.timestamp,
286
286
  slotNumber: constants.slotNumber,
287
287
  coinbase: constants.coinbase,
288
288
  feeRecipient: constants.feeRecipient,
@@ -55,6 +55,7 @@ export class BlockProvingState {
55
55
  | ProofState<BlockRollupPublicInputs, typeof NESTED_RECURSIVE_ROLLUP_HONK_PROOF_LENGTH>
56
56
  | undefined;
57
57
  private builtBlockHeader: BlockHeader | undefined;
58
+ private builtArchive: AppendOnlyTreeSnapshot | undefined;
58
59
  private endState: StateReference | undefined;
59
60
  private endSpongeBlob: SpongeBlob | undefined;
60
61
  private txs: TxProvingState[] = [];
@@ -232,6 +233,14 @@ export class BlockProvingState {
232
233
  return this.builtBlockHeader;
233
234
  }
234
235
 
236
+ public setBuiltArchive(archive: AppendOnlyTreeSnapshot) {
237
+ this.builtArchive = archive;
238
+ }
239
+
240
+ public getBuiltArchive() {
241
+ return this.builtArchive;
242
+ }
243
+
235
244
  public getStartSpongeBlob() {
236
245
  return this.startSpongeBlob;
237
246
  }
@@ -11,6 +11,7 @@ import {
11
11
  type L1_TO_L2_MSG_SUBTREE_ROOT_SIBLING_PATH_LENGTH,
12
12
  type NESTED_RECURSIVE_ROLLUP_HONK_PROOF_LENGTH,
13
13
  NUM_MSGS_PER_BASE_PARITY,
14
+ OUT_HASH_TREE_HEIGHT,
14
15
  } from '@aztec/constants';
15
16
  import { BlockNumber } from '@aztec/foundation/branded-types';
16
17
  import { padArrayEnd } from '@aztec/foundation/collection';
@@ -19,6 +20,7 @@ import { Fr } from '@aztec/foundation/curves/bn254';
19
20
  import type { Tuple } from '@aztec/foundation/serialize';
20
21
  import { type TreeNodeLocation, UnbalancedTreeStore } from '@aztec/foundation/trees';
21
22
  import type { PublicInputsAndRecursiveProof } from '@aztec/stdlib/interfaces/server';
23
+ import { computeCheckpointOutHash } from '@aztec/stdlib/messaging';
22
24
  import { ParityBasePrivateInputs } from '@aztec/stdlib/parity';
23
25
  import {
24
26
  BlockMergeRollupPrivateInputs,
@@ -38,6 +40,11 @@ import { accumulateBlobs, buildBlobHints, toProofData } from './block-building-h
38
40
  import { BlockProvingState, type ProofState } from './block-proving-state.js';
39
41
  import type { EpochProvingState } from './epoch-proving-state.js';
40
42
 
43
+ type OutHashHint = {
44
+ treeSnapshot: AppendOnlyTreeSnapshot;
45
+ siblingPath: Tuple<Fr, typeof OUT_HASH_TREE_HEIGHT>;
46
+ };
47
+
41
48
  export class CheckpointProvingState {
42
49
  private blockProofs: UnbalancedTreeStore<
43
50
  ProofState<BlockRollupPublicInputs, typeof NESTED_RECURSIVE_ROLLUP_HONK_PROOF_LENGTH>
@@ -46,6 +53,11 @@ export class CheckpointProvingState {
46
53
  | ProofState<CheckpointRollupPublicInputs, typeof NESTED_RECURSIVE_ROLLUP_HONK_PROOF_LENGTH>
47
54
  | undefined;
48
55
  private blocks: (BlockProvingState | undefined)[] = [];
56
+ private previousOutHashHint: OutHashHint | undefined;
57
+ private outHash: Fr | undefined;
58
+ // The snapshot and sibling path after the checkpoint's out hash is inserted.
59
+ // Stored here to be retrieved for the next checkpoint when it's added.
60
+ private newOutHashHint: OutHashHint | undefined;
49
61
  private startBlobAccumulator: BatchedBlobAccumulator | undefined;
50
62
  private endBlobAccumulator: BatchedBlobAccumulator | undefined;
51
63
  private blobFields: Fr[] | undefined;
@@ -73,7 +85,7 @@ export class CheckpointProvingState {
73
85
  typeof L1_TO_L2_MSG_SUBTREE_ROOT_SIBLING_PATH_LENGTH
74
86
  >,
75
87
  public parentEpoch: EpochProvingState,
76
- private onBlobAccumulatorSet: (checkpoint: CheckpointProvingState) => void,
88
+ private onBlobAccumulatorSet: (checkpoint: CheckpointProvingState) => Promise<void>,
77
89
  ) {
78
90
  this.blockProofs = new UnbalancedTreeStore(totalNumBlocks);
79
91
  this.firstBlockNumber = BlockNumber(headerOfLastBlockInPreviousCheckpoint.globalVariables.blockNumber + 1);
@@ -192,7 +204,36 @@ export class CheckpointProvingState {
192
204
  Fr.ZERO,
193
205
  NUM_MSGS_PER_BASE_PARITY,
194
206
  );
195
- return new ParityBasePrivateInputs(messages, this.constants.vkTreeRoot);
207
+ return new ParityBasePrivateInputs(messages, this.constants.vkTreeRoot, this.constants.proverId);
208
+ }
209
+
210
+ public setOutHashHint(hint: OutHashHint) {
211
+ this.previousOutHashHint = hint;
212
+ }
213
+
214
+ public getOutHashHint() {
215
+ return this.previousOutHashHint;
216
+ }
217
+
218
+ public accumulateBlockOutHashes() {
219
+ if (this.isAcceptingBlocks() || this.blocks.some(b => !b?.hasEndState())) {
220
+ return;
221
+ }
222
+
223
+ if (!this.outHash) {
224
+ const messagesPerBlock = this.blocks.map(b => b!.getTxEffects().map(tx => tx.l2ToL1Msgs));
225
+ this.outHash = computeCheckpointOutHash(messagesPerBlock);
226
+ }
227
+
228
+ return this.outHash;
229
+ }
230
+
231
+ public setOutHashHintForNextCheckpoint(hint: OutHashHint) {
232
+ this.newOutHashHint = hint;
233
+ }
234
+
235
+ public getOutHashHintForNextCheckpoint() {
236
+ return this.newOutHashHint;
196
237
  }
197
238
 
198
239
  public async accumulateBlobs(startBlobAccumulator: BatchedBlobAccumulator) {
@@ -204,7 +245,7 @@ export class CheckpointProvingState {
204
245
  this.endBlobAccumulator = await accumulateBlobs(this.blobFields!, startBlobAccumulator);
205
246
  this.startBlobAccumulator = startBlobAccumulator;
206
247
 
207
- this.onBlobAccumulatorSet(this);
248
+ await this.onBlobAccumulatorSet(this);
208
249
 
209
250
  return this.endBlobAccumulator;
210
251
  }
@@ -230,12 +271,15 @@ export class CheckpointProvingState {
230
271
  return this.totalNumBlocks === 1 ? 'rollup-checkpoint-root-single-block' : 'rollup-checkpoint-root';
231
272
  }
232
273
 
233
- public getCheckpointRootRollupInputs() {
274
+ public async getCheckpointRootRollupInputs() {
234
275
  const proofs = this.#getChildProofsForRoot();
235
276
  const nonEmptyProofs = proofs.filter(p => !!p);
236
277
  if (proofs.length !== nonEmptyProofs.length) {
237
278
  throw new Error('At least one child is not ready for the checkpoint root rollup.');
238
279
  }
280
+ if (!this.previousOutHashHint) {
281
+ throw new Error('Out hash hint is not set.');
282
+ }
239
283
  if (!this.startBlobAccumulator) {
240
284
  throw new Error('Start blob accumulator is not set.');
241
285
  }
@@ -243,11 +287,13 @@ export class CheckpointProvingState {
243
287
  // `blobFields` must've been set if `startBlobAccumulator` is set (in `accumulateBlobs`).
244
288
  const blobFields = this.blobFields!;
245
289
 
246
- const { blobCommitments, blobsHash } = buildBlobHints(blobFields);
290
+ const { blobCommitments, blobsHash } = await buildBlobHints(blobFields);
247
291
 
248
292
  const hints = CheckpointRootRollupHints.from({
249
293
  previousBlockHeader: this.headerOfLastBlockInPreviousCheckpoint,
250
294
  previousArchiveSiblingPath: this.lastArchiveSiblingPath,
295
+ previousOutHash: this.previousOutHashHint.treeSnapshot,
296
+ newOutHashSiblingPath: this.previousOutHashHint.siblingPath,
251
297
  startBlobAccumulator: this.startBlobAccumulator.toBlobAccumulator(),
252
298
  finalBlobChallenges: this.finalBlobBatchingChallenges,
253
299
  blobFields: padArrayEnd(blobFields, Fr.ZERO, FIELDS_PER_BLOB * BLOBS_PER_CHECKPOINT),
@@ -273,7 +319,7 @@ export class CheckpointProvingState {
273
319
 
274
320
  public isReadyForCheckpointRoot() {
275
321
  const allChildProofsReady = this.#getChildProofsForRoot().every(p => !!p);
276
- return allChildProofsReady && !!this.startBlobAccumulator;
322
+ return allChildProofsReady && !!this.previousOutHashHint && !!this.startBlobAccumulator;
277
323
  }
278
324
 
279
325
  public verifyState() {
@@ -300,4 +346,17 @@ export class CheckpointProvingState {
300
346
  ? [this.blockProofs.getNode(rootLocation)?.provingOutput] // If there's only 1 block, its proof will be stored at the root.
301
347
  : this.blockProofs.getChildren(rootLocation).map(c => c?.provingOutput);
302
348
  }
349
+
350
+ /**
351
+ * Returns the block-level proof outputs that feed into the checkpoint root rollup.
352
+ * Used by `CheckpointSubTreeOrchestrator` to surface its sub-tree result.
353
+ */
354
+ public getSubTreeOutputProofs() {
355
+ return this.#getChildProofsForRoot();
356
+ }
357
+
358
+ /** Sibling path of the archive tree captured before any block in this checkpoint landed. */
359
+ public getLastArchiveSiblingPath() {
360
+ return this.lastArchiveSiblingPath;
361
+ }
303
362
  }