@aztec/prover-client 0.0.0-test.1 → 0.0.1-commit.017a351

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 (185) hide show
  1. package/dest/config.d.ts +8 -8
  2. package/dest/config.d.ts.map +1 -1
  3. package/dest/config.js +26 -2
  4. package/dest/index.d.ts +1 -1
  5. package/dest/light/index.d.ts +2 -0
  6. package/dest/light/index.d.ts.map +1 -0
  7. package/dest/light/index.js +1 -0
  8. package/dest/light/lightweight_checkpoint_builder.d.ts +52 -0
  9. package/dest/light/lightweight_checkpoint_builder.d.ts.map +1 -0
  10. package/dest/light/lightweight_checkpoint_builder.js +231 -0
  11. package/dest/mocks/fixtures.d.ts +8 -8
  12. package/dest/mocks/fixtures.d.ts.map +1 -1
  13. package/dest/mocks/fixtures.js +36 -17
  14. package/dest/mocks/test_context.d.ts +45 -32
  15. package/dest/mocks/test_context.d.ts.map +1 -1
  16. package/dest/mocks/test_context.js +162 -90
  17. package/dest/orchestrator/block-building-helpers.d.ts +36 -29
  18. package/dest/orchestrator/block-building-helpers.d.ts.map +1 -1
  19. package/dest/orchestrator/block-building-helpers.js +170 -189
  20. package/dest/orchestrator/block-proving-state.d.ts +73 -48
  21. package/dest/orchestrator/block-proving-state.d.ts.map +1 -1
  22. package/dest/orchestrator/block-proving-state.js +289 -177
  23. package/dest/orchestrator/checkpoint-proving-state.d.ts +83 -0
  24. package/dest/orchestrator/checkpoint-proving-state.d.ts.map +1 -0
  25. package/dest/orchestrator/checkpoint-proving-state.js +252 -0
  26. package/dest/orchestrator/checkpoint-sub-tree-orchestrator.d.ts +107 -0
  27. package/dest/orchestrator/checkpoint-sub-tree-orchestrator.d.ts.map +1 -0
  28. package/dest/orchestrator/checkpoint-sub-tree-orchestrator.js +151 -0
  29. package/dest/orchestrator/epoch-proving-context.d.ts +51 -0
  30. package/dest/orchestrator/epoch-proving-context.d.ts.map +1 -0
  31. package/dest/orchestrator/epoch-proving-context.js +81 -0
  32. package/dest/orchestrator/epoch-proving-state.d.ts +43 -28
  33. package/dest/orchestrator/epoch-proving-state.d.ts.map +1 -1
  34. package/dest/orchestrator/epoch-proving-state.js +179 -73
  35. package/dest/orchestrator/index.d.ts +4 -1
  36. package/dest/orchestrator/index.d.ts.map +1 -1
  37. package/dest/orchestrator/index.js +3 -0
  38. package/dest/orchestrator/orchestrator.d.ts +59 -51
  39. package/dest/orchestrator/orchestrator.d.ts.map +1 -1
  40. package/dest/orchestrator/orchestrator.js +808 -385
  41. package/dest/orchestrator/orchestrator_metrics.d.ts +1 -1
  42. package/dest/orchestrator/orchestrator_metrics.d.ts.map +1 -1
  43. package/dest/orchestrator/orchestrator_metrics.js +2 -6
  44. package/dest/orchestrator/proving-scheduler.d.ts +72 -0
  45. package/dest/orchestrator/proving-scheduler.d.ts.map +1 -0
  46. package/dest/orchestrator/proving-scheduler.js +117 -0
  47. package/dest/orchestrator/top-tree-orchestrator.d.ts +83 -0
  48. package/dest/orchestrator/top-tree-orchestrator.d.ts.map +1 -0
  49. package/dest/orchestrator/top-tree-orchestrator.js +182 -0
  50. package/dest/orchestrator/top-tree-proving-scheduler.d.ts +62 -0
  51. package/dest/orchestrator/top-tree-proving-scheduler.d.ts.map +1 -0
  52. package/dest/orchestrator/top-tree-proving-scheduler.js +73 -0
  53. package/dest/orchestrator/top-tree-proving-state.d.ts +61 -0
  54. package/dest/orchestrator/top-tree-proving-state.d.ts.map +1 -0
  55. package/dest/orchestrator/top-tree-proving-state.js +185 -0
  56. package/dest/orchestrator/tx-proving-state.d.ts +15 -12
  57. package/dest/orchestrator/tx-proving-state.d.ts.map +1 -1
  58. package/dest/orchestrator/tx-proving-state.js +27 -44
  59. package/dest/prover-client/factory.d.ts +3 -3
  60. package/dest/prover-client/factory.d.ts.map +1 -1
  61. package/dest/prover-client/index.d.ts +1 -1
  62. package/dest/prover-client/prover-client.d.ts +68 -9
  63. package/dest/prover-client/prover-client.d.ts.map +1 -1
  64. package/dest/prover-client/prover-client.js +68 -14
  65. package/dest/prover-client/server-epoch-prover.d.ts +16 -12
  66. package/dest/prover-client/server-epoch-prover.d.ts.map +1 -1
  67. package/dest/prover-client/server-epoch-prover.js +11 -11
  68. package/dest/proving_broker/broker_prover_facade.d.ts +28 -19
  69. package/dest/proving_broker/broker_prover_facade.d.ts.map +1 -1
  70. package/dest/proving_broker/broker_prover_facade.js +74 -61
  71. package/dest/proving_broker/config.d.ts +18 -61
  72. package/dest/proving_broker/config.d.ts.map +1 -1
  73. package/dest/proving_broker/config.js +43 -9
  74. package/dest/proving_broker/factory.d.ts +2 -2
  75. package/dest/proving_broker/factory.d.ts.map +1 -1
  76. package/dest/proving_broker/factory.js +5 -1
  77. package/dest/proving_broker/fixtures.d.ts +3 -2
  78. package/dest/proving_broker/fixtures.d.ts.map +1 -1
  79. package/dest/proving_broker/fixtures.js +3 -2
  80. package/dest/proving_broker/index.d.ts +2 -1
  81. package/dest/proving_broker/index.d.ts.map +1 -1
  82. package/dest/proving_broker/index.js +1 -0
  83. package/dest/proving_broker/proof_store/factory.d.ts +2 -5
  84. package/dest/proving_broker/proof_store/factory.d.ts.map +1 -1
  85. package/dest/proving_broker/proof_store/factory.js +7 -30
  86. package/dest/proving_broker/proof_store/file_store_proof_store.d.ts +18 -0
  87. package/dest/proving_broker/proof_store/file_store_proof_store.d.ts.map +1 -0
  88. package/dest/proving_broker/proof_store/file_store_proof_store.js +60 -0
  89. package/dest/proving_broker/proof_store/index.d.ts +2 -1
  90. package/dest/proving_broker/proof_store/index.d.ts.map +1 -1
  91. package/dest/proving_broker/proof_store/index.js +1 -0
  92. package/dest/proving_broker/proof_store/inline_proof_store.d.ts +1 -1
  93. package/dest/proving_broker/proof_store/inline_proof_store.d.ts.map +1 -1
  94. package/dest/proving_broker/proof_store/proof_store.d.ts +1 -1
  95. package/dest/proving_broker/proving_agent.d.ts +8 -12
  96. package/dest/proving_broker/proving_agent.d.ts.map +1 -1
  97. package/dest/proving_broker/proving_agent.js +86 -65
  98. package/dest/proving_broker/proving_broker.d.ts +18 -6
  99. package/dest/proving_broker/proving_broker.d.ts.map +1 -1
  100. package/dest/proving_broker/proving_broker.js +108 -44
  101. package/dest/proving_broker/proving_broker_database/memory.d.ts +3 -2
  102. package/dest/proving_broker/proving_broker_database/memory.d.ts.map +1 -1
  103. package/dest/proving_broker/proving_broker_database/memory.js +1 -1
  104. package/dest/proving_broker/proving_broker_database/persisted.d.ts +5 -3
  105. package/dest/proving_broker/proving_broker_database/persisted.d.ts.map +1 -1
  106. package/dest/proving_broker/proving_broker_database/persisted.js +401 -11
  107. package/dest/proving_broker/proving_broker_database.d.ts +3 -2
  108. package/dest/proving_broker/proving_broker_database.d.ts.map +1 -1
  109. package/dest/proving_broker/proving_broker_instrumentation.d.ts +3 -1
  110. package/dest/proving_broker/proving_broker_instrumentation.d.ts.map +1 -1
  111. package/dest/proving_broker/proving_broker_instrumentation.js +22 -35
  112. package/dest/proving_broker/proving_job_controller.d.ts +11 -10
  113. package/dest/proving_broker/proving_job_controller.d.ts.map +1 -1
  114. package/dest/proving_broker/proving_job_controller.js +92 -62
  115. package/dest/proving_broker/rpc.d.ts +9 -7
  116. package/dest/proving_broker/rpc.d.ts.map +1 -1
  117. package/dest/proving_broker/rpc.js +88 -27
  118. package/dest/test/mock_proof_store.d.ts +9 -0
  119. package/dest/test/mock_proof_store.d.ts.map +1 -0
  120. package/dest/test/mock_proof_store.js +10 -0
  121. package/dest/test/mock_prover.d.ts +23 -17
  122. package/dest/test/mock_prover.d.ts.map +1 -1
  123. package/dest/test/mock_prover.js +38 -20
  124. package/package.json +34 -33
  125. package/src/config.ts +41 -9
  126. package/src/light/index.ts +1 -0
  127. package/src/light/lightweight_checkpoint_builder.ts +320 -0
  128. package/src/mocks/fixtures.ts +46 -40
  129. package/src/mocks/test_context.ts +231 -120
  130. package/src/orchestrator/block-building-helpers.ts +258 -334
  131. package/src/orchestrator/block-proving-state.ts +334 -231
  132. package/src/orchestrator/checkpoint-proving-state.ts +362 -0
  133. package/src/orchestrator/checkpoint-sub-tree-orchestrator.ts +271 -0
  134. package/src/orchestrator/epoch-proving-context.ts +101 -0
  135. package/src/orchestrator/epoch-proving-state.ts +239 -111
  136. package/src/orchestrator/index.ts +8 -0
  137. package/src/orchestrator/orchestrator.ts +591 -451
  138. package/src/orchestrator/orchestrator_metrics.ts +2 -6
  139. package/src/orchestrator/proving-scheduler.ts +156 -0
  140. package/src/orchestrator/top-tree-orchestrator.ts +314 -0
  141. package/src/orchestrator/top-tree-proving-scheduler.ts +154 -0
  142. package/src/orchestrator/top-tree-proving-state.ts +220 -0
  143. package/src/orchestrator/tx-proving-state.ts +48 -66
  144. package/src/prover-client/factory.ts +6 -2
  145. package/src/prover-client/prover-client.ts +173 -38
  146. package/src/prover-client/server-epoch-prover.ts +40 -22
  147. package/src/proving_broker/broker_prover_facade.ts +227 -149
  148. package/src/proving_broker/config.ts +49 -8
  149. package/src/proving_broker/factory.ts +2 -1
  150. package/src/proving_broker/fixtures.ts +8 -3
  151. package/src/proving_broker/index.ts +1 -0
  152. package/src/proving_broker/proof_store/factory.ts +10 -32
  153. package/src/proving_broker/proof_store/file_store_proof_store.ts +78 -0
  154. package/src/proving_broker/proof_store/index.ts +1 -0
  155. package/src/proving_broker/proof_store/inline_proof_store.ts +1 -1
  156. package/src/proving_broker/proving_agent.ts +95 -66
  157. package/src/proving_broker/proving_broker.ts +121 -49
  158. package/src/proving_broker/proving_broker_database/memory.ts +3 -2
  159. package/src/proving_broker/proving_broker_database/persisted.ts +31 -15
  160. package/src/proving_broker/proving_broker_database.ts +2 -1
  161. package/src/proving_broker/proving_broker_instrumentation.ts +23 -35
  162. package/src/proving_broker/proving_job_controller.ts +100 -83
  163. package/src/proving_broker/rpc.ts +46 -25
  164. package/src/test/mock_proof_store.ts +14 -0
  165. package/src/test/mock_prover.ts +156 -64
  166. package/dest/bin/get-proof-inputs.d.ts +0 -2
  167. package/dest/bin/get-proof-inputs.d.ts.map +0 -1
  168. package/dest/bin/get-proof-inputs.js +0 -51
  169. package/dest/block_builder/index.d.ts +0 -6
  170. package/dest/block_builder/index.d.ts.map +0 -1
  171. package/dest/block_builder/index.js +0 -1
  172. package/dest/block_builder/light.d.ts +0 -33
  173. package/dest/block_builder/light.d.ts.map +0 -1
  174. package/dest/block_builder/light.js +0 -82
  175. package/dest/proving_broker/proof_store/gcs_proof_store.d.ts +0 -14
  176. package/dest/proving_broker/proof_store/gcs_proof_store.d.ts.map +0 -1
  177. package/dest/proving_broker/proof_store/gcs_proof_store.js +0 -51
  178. package/dest/proving_broker/proving_agent_instrumentation.d.ts +0 -8
  179. package/dest/proving_broker/proving_agent_instrumentation.d.ts.map +0 -1
  180. package/dest/proving_broker/proving_agent_instrumentation.js +0 -16
  181. package/src/bin/get-proof-inputs.ts +0 -59
  182. package/src/block_builder/index.ts +0 -6
  183. package/src/block_builder/light.ts +0 -101
  184. package/src/proving_broker/proof_store/gcs_proof_store.ts +0 -72
  185. package/src/proving_broker/proving_agent_instrumentation.ts +0 -21
@@ -0,0 +1,362 @@
1
+ import {
2
+ BatchedBlobAccumulator,
3
+ type FinalBlobBatchingChallenges,
4
+ SpongeBlob,
5
+ encodeCheckpointBlobDataFromBlocks,
6
+ } from '@aztec/blob-lib';
7
+ import {
8
+ type ARCHIVE_HEIGHT,
9
+ BLOBS_PER_CHECKPOINT,
10
+ FIELDS_PER_BLOB,
11
+ type L1_TO_L2_MSG_SUBTREE_ROOT_SIBLING_PATH_LENGTH,
12
+ type NESTED_RECURSIVE_ROLLUP_HONK_PROOF_LENGTH,
13
+ NUM_MSGS_PER_BASE_PARITY,
14
+ OUT_HASH_TREE_HEIGHT,
15
+ } from '@aztec/constants';
16
+ import { BlockNumber } from '@aztec/foundation/branded-types';
17
+ import { padArrayEnd } from '@aztec/foundation/collection';
18
+ import { BLS12Point } from '@aztec/foundation/curves/bls12';
19
+ import { Fr } from '@aztec/foundation/curves/bn254';
20
+ import type { Tuple } from '@aztec/foundation/serialize';
21
+ import { type TreeNodeLocation, UnbalancedTreeStore } from '@aztec/foundation/trees';
22
+ import type { PublicInputsAndRecursiveProof } from '@aztec/stdlib/interfaces/server';
23
+ import { computeCheckpointOutHash } from '@aztec/stdlib/messaging';
24
+ import { ParityBasePrivateInputs } from '@aztec/stdlib/parity';
25
+ import {
26
+ BlockMergeRollupPrivateInputs,
27
+ BlockRollupPublicInputs,
28
+ CheckpointConstantData,
29
+ CheckpointRollupPublicInputs,
30
+ CheckpointRootRollupHints,
31
+ CheckpointRootRollupPrivateInputs,
32
+ CheckpointRootSingleBlockRollupPrivateInputs,
33
+ } from '@aztec/stdlib/rollup';
34
+ import type { CircuitName } from '@aztec/stdlib/stats';
35
+ import type { AppendOnlyTreeSnapshot } from '@aztec/stdlib/trees';
36
+ import type { BlockHeader } from '@aztec/stdlib/tx';
37
+ import type { UInt64 } from '@aztec/stdlib/types';
38
+
39
+ import { accumulateBlobs, buildBlobHints, toProofData } from './block-building-helpers.js';
40
+ import { BlockProvingState, type ProofState } from './block-proving-state.js';
41
+ import type { EpochProvingState } from './epoch-proving-state.js';
42
+
43
+ type OutHashHint = {
44
+ treeSnapshot: AppendOnlyTreeSnapshot;
45
+ siblingPath: Tuple<Fr, typeof OUT_HASH_TREE_HEIGHT>;
46
+ };
47
+
48
+ export class CheckpointProvingState {
49
+ private blockProofs: UnbalancedTreeStore<
50
+ ProofState<BlockRollupPublicInputs, typeof NESTED_RECURSIVE_ROLLUP_HONK_PROOF_LENGTH>
51
+ >;
52
+ private checkpointRootProof:
53
+ | ProofState<CheckpointRollupPublicInputs, typeof NESTED_RECURSIVE_ROLLUP_HONK_PROOF_LENGTH>
54
+ | undefined;
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;
61
+ private startBlobAccumulator: BatchedBlobAccumulator | undefined;
62
+ private endBlobAccumulator: BatchedBlobAccumulator | undefined;
63
+ private blobFields: Fr[] | undefined;
64
+ private error: string | undefined;
65
+ public readonly firstBlockNumber: BlockNumber;
66
+
67
+ constructor(
68
+ public readonly index: number,
69
+ public readonly constants: CheckpointConstantData,
70
+ public readonly totalNumBlocks: number,
71
+ private readonly finalBlobBatchingChallenges: FinalBlobBatchingChallenges,
72
+ private readonly headerOfLastBlockInPreviousCheckpoint: BlockHeader,
73
+ private readonly lastArchiveSiblingPath: Tuple<Fr, typeof ARCHIVE_HEIGHT>,
74
+ private readonly l1ToL2Messages: Fr[],
75
+ // The snapshot and sibling path before the new l1 to l2 message subtree is inserted.
76
+ private readonly lastL1ToL2MessageTreeSnapshot: AppendOnlyTreeSnapshot,
77
+ private readonly lastL1ToL2MessageSubtreeRootSiblingPath: Tuple<
78
+ Fr,
79
+ typeof L1_TO_L2_MSG_SUBTREE_ROOT_SIBLING_PATH_LENGTH
80
+ >,
81
+ // The snapshot and sibling path after the new l1 to l2 message subtree is inserted.
82
+ private readonly newL1ToL2MessageTreeSnapshot: AppendOnlyTreeSnapshot,
83
+ private readonly newL1ToL2MessageSubtreeRootSiblingPath: Tuple<
84
+ Fr,
85
+ typeof L1_TO_L2_MSG_SUBTREE_ROOT_SIBLING_PATH_LENGTH
86
+ >,
87
+ public parentEpoch: EpochProvingState,
88
+ private onBlobAccumulatorSet: (checkpoint: CheckpointProvingState) => Promise<void>,
89
+ ) {
90
+ this.blockProofs = new UnbalancedTreeStore(totalNumBlocks);
91
+ this.firstBlockNumber = BlockNumber(headerOfLastBlockInPreviousCheckpoint.globalVariables.blockNumber + 1);
92
+ }
93
+
94
+ public get epochNumber(): number {
95
+ return this.parentEpoch.epochNumber;
96
+ }
97
+
98
+ public startNewBlock(
99
+ blockNumber: BlockNumber,
100
+ timestamp: UInt64,
101
+ totalNumTxs: number,
102
+ lastArchiveTreeSnapshot: AppendOnlyTreeSnapshot,
103
+ lastArchiveSiblingPath: Tuple<Fr, typeof ARCHIVE_HEIGHT>,
104
+ ): BlockProvingState {
105
+ const index = Number(blockNumber) - Number(this.firstBlockNumber);
106
+ if (index >= this.totalNumBlocks) {
107
+ throw new Error(`Unable to start a new block at index ${index}. Expected at most ${this.totalNumBlocks} blocks.`);
108
+ }
109
+
110
+ // If this is the first block, we use the snapshot and sibling path before the new l1 to l2 messages are inserted.
111
+ // Otherwise, we use the snapshot and sibling path after the new l1 to l2 messages are inserted, which will always
112
+ // happen in the first block.
113
+ const lastL1ToL2MessageTreeSnapshot =
114
+ index === 0 ? this.lastL1ToL2MessageTreeSnapshot : this.newL1ToL2MessageTreeSnapshot;
115
+ const lastL1ToL2MessageSubtreeRootSiblingPath =
116
+ index === 0 ? this.lastL1ToL2MessageSubtreeRootSiblingPath : this.newL1ToL2MessageSubtreeRootSiblingPath;
117
+
118
+ const startSpongeBlob = index === 0 ? SpongeBlob.init() : this.blocks[index - 1]?.getEndSpongeBlob();
119
+ if (!startSpongeBlob) {
120
+ throw new Error(
121
+ 'Cannot start a new block before the trees have progressed from the tx effects in the previous block.',
122
+ );
123
+ }
124
+
125
+ const block = new BlockProvingState(
126
+ index,
127
+ blockNumber,
128
+ totalNumTxs,
129
+ this.constants,
130
+ timestamp,
131
+ lastArchiveTreeSnapshot,
132
+ lastArchiveSiblingPath,
133
+ lastL1ToL2MessageTreeSnapshot,
134
+ lastL1ToL2MessageSubtreeRootSiblingPath,
135
+ this.newL1ToL2MessageTreeSnapshot,
136
+ this.headerOfLastBlockInPreviousCheckpoint,
137
+ startSpongeBlob,
138
+ this,
139
+ );
140
+ this.blocks[index] = block;
141
+
142
+ return block;
143
+ }
144
+
145
+ // Returns true if we are still able to accept blocks, false otherwise.
146
+ public isAcceptingBlocks() {
147
+ return this.blocks.filter(b => !!b).length < this.totalNumBlocks;
148
+ }
149
+
150
+ public setBlockRootRollupProof(
151
+ blockIndex: number,
152
+ provingOutput: PublicInputsAndRecursiveProof<
153
+ BlockRollupPublicInputs,
154
+ typeof NESTED_RECURSIVE_ROLLUP_HONK_PROOF_LENGTH
155
+ >,
156
+ ): TreeNodeLocation {
157
+ return this.blockProofs.setLeaf(blockIndex, { provingOutput });
158
+ }
159
+
160
+ public tryStartProvingBlockMerge(location: TreeNodeLocation) {
161
+ if (this.blockProofs.getNode(location)?.isProving) {
162
+ return false;
163
+ } else {
164
+ this.blockProofs.setNode(location, { isProving: true });
165
+ return true;
166
+ }
167
+ }
168
+
169
+ public setBlockMergeRollupProof(
170
+ location: TreeNodeLocation,
171
+ provingOutput: PublicInputsAndRecursiveProof<
172
+ BlockRollupPublicInputs,
173
+ typeof NESTED_RECURSIVE_ROLLUP_HONK_PROOF_LENGTH
174
+ >,
175
+ ) {
176
+ this.blockProofs.setNode(location, { provingOutput });
177
+ }
178
+
179
+ public tryStartProvingCheckpointRoot() {
180
+ if (this.checkpointRootProof?.isProving) {
181
+ return false;
182
+ } else {
183
+ this.checkpointRootProof = { isProving: true };
184
+ return true;
185
+ }
186
+ }
187
+
188
+ public setCheckpointRootRollupProof(
189
+ provingOutput: PublicInputsAndRecursiveProof<
190
+ CheckpointRollupPublicInputs,
191
+ typeof NESTED_RECURSIVE_ROLLUP_HONK_PROOF_LENGTH
192
+ >,
193
+ ): TreeNodeLocation {
194
+ this.checkpointRootProof = { provingOutput };
195
+ return this.parentEpoch.setCheckpointRootRollupProof(this.index, provingOutput);
196
+ }
197
+
198
+ public getBaseParityInputs(baseParityIndex: number) {
199
+ const messages = padArrayEnd(
200
+ this.l1ToL2Messages.slice(
201
+ baseParityIndex * NUM_MSGS_PER_BASE_PARITY,
202
+ (baseParityIndex + 1) * NUM_MSGS_PER_BASE_PARITY,
203
+ ),
204
+ Fr.ZERO,
205
+ NUM_MSGS_PER_BASE_PARITY,
206
+ );
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;
237
+ }
238
+
239
+ public async accumulateBlobs(startBlobAccumulator: BatchedBlobAccumulator) {
240
+ if (this.isAcceptingBlocks() || this.blocks.some(b => !b?.hasEndState())) {
241
+ return;
242
+ }
243
+
244
+ this.blobFields = encodeCheckpointBlobDataFromBlocks(this.blocks.map(b => b!.getBlockBlobData()));
245
+ this.endBlobAccumulator = await accumulateBlobs(this.blobFields!, startBlobAccumulator);
246
+ this.startBlobAccumulator = startBlobAccumulator;
247
+
248
+ await this.onBlobAccumulatorSet(this);
249
+
250
+ return this.endBlobAccumulator;
251
+ }
252
+
253
+ public getEndBlobAccumulator() {
254
+ return this.endBlobAccumulator;
255
+ }
256
+
257
+ public getParentLocation(location: TreeNodeLocation) {
258
+ return this.blockProofs.getParentLocation(location);
259
+ }
260
+
261
+ public getBlockMergeRollupInputs(mergeLocation: TreeNodeLocation) {
262
+ const [left, right] = this.blockProofs.getChildren(mergeLocation).map(c => c?.provingOutput);
263
+ if (!left || !right) {
264
+ throw new Error('At least one child is not ready for the block merge rollup.');
265
+ }
266
+
267
+ return new BlockMergeRollupPrivateInputs([toProofData(left), toProofData(right)]);
268
+ }
269
+
270
+ public getCheckpointRootRollupType(): CircuitName {
271
+ return this.totalNumBlocks === 1 ? 'rollup-checkpoint-root-single-block' : 'rollup-checkpoint-root';
272
+ }
273
+
274
+ public async getCheckpointRootRollupInputs() {
275
+ const proofs = this.#getChildProofsForRoot();
276
+ const nonEmptyProofs = proofs.filter(p => !!p);
277
+ if (proofs.length !== nonEmptyProofs.length) {
278
+ throw new Error('At least one child is not ready for the checkpoint root rollup.');
279
+ }
280
+ if (!this.previousOutHashHint) {
281
+ throw new Error('Out hash hint is not set.');
282
+ }
283
+ if (!this.startBlobAccumulator) {
284
+ throw new Error('Start blob accumulator is not set.');
285
+ }
286
+
287
+ // `blobFields` must've been set if `startBlobAccumulator` is set (in `accumulateBlobs`).
288
+ const blobFields = this.blobFields!;
289
+
290
+ const { blobCommitments, blobsHash } = await buildBlobHints(blobFields);
291
+
292
+ const hints = CheckpointRootRollupHints.from({
293
+ previousBlockHeader: this.headerOfLastBlockInPreviousCheckpoint,
294
+ previousArchiveSiblingPath: this.lastArchiveSiblingPath,
295
+ previousOutHash: this.previousOutHashHint.treeSnapshot,
296
+ newOutHashSiblingPath: this.previousOutHashHint.siblingPath,
297
+ startBlobAccumulator: this.startBlobAccumulator.toBlobAccumulator(),
298
+ finalBlobChallenges: this.finalBlobBatchingChallenges,
299
+ blobFields: padArrayEnd(blobFields, Fr.ZERO, FIELDS_PER_BLOB * BLOBS_PER_CHECKPOINT),
300
+ blobCommitments: padArrayEnd(blobCommitments, BLS12Point.ZERO, BLOBS_PER_CHECKPOINT),
301
+ blobsHash,
302
+ });
303
+
304
+ const [left, right] = nonEmptyProofs.map(p => toProofData(p));
305
+
306
+ return !right
307
+ ? new CheckpointRootSingleBlockRollupPrivateInputs(left, hints)
308
+ : new CheckpointRootRollupPrivateInputs([left, right], hints);
309
+ }
310
+
311
+ public getBlockProvingStateByBlockNumber(blockNumber: BlockNumber) {
312
+ const index = Number(blockNumber) - Number(this.firstBlockNumber);
313
+ return this.blocks[index];
314
+ }
315
+
316
+ public isReadyForBlockMerge(location: TreeNodeLocation) {
317
+ return !!this.blockProofs.getSibling(location)?.provingOutput;
318
+ }
319
+
320
+ public isReadyForCheckpointRoot() {
321
+ const allChildProofsReady = this.#getChildProofsForRoot().every(p => !!p);
322
+ return allChildProofsReady && !!this.previousOutHashHint && !!this.startBlobAccumulator;
323
+ }
324
+
325
+ public verifyState() {
326
+ return this.parentEpoch.verifyState();
327
+ }
328
+
329
+ public getError() {
330
+ return this.error;
331
+ }
332
+
333
+ // Attempts to reject the proving state promise with a reason of 'cancelled'
334
+ public cancel() {
335
+ this.reject('Proving cancelled');
336
+ }
337
+
338
+ public reject(reason: string) {
339
+ this.error = reason;
340
+ this.parentEpoch.reject(reason);
341
+ }
342
+
343
+ #getChildProofsForRoot() {
344
+ const rootLocation = { level: 0, index: 0 };
345
+ return this.totalNumBlocks === 1
346
+ ? [this.blockProofs.getNode(rootLocation)?.provingOutput] // If there's only 1 block, its proof will be stored at the root.
347
+ : this.blockProofs.getChildren(rootLocation).map(c => c?.provingOutput);
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
+ }
362
+ }
@@ -0,0 +1,271 @@
1
+ import { FinalBlobBatchingChallenges } from '@aztec/blob-lib';
2
+ import type { ARCHIVE_HEIGHT, NESTED_RECURSIVE_ROLLUP_HONK_PROOF_LENGTH } from '@aztec/constants';
3
+ import type { EpochNumber } from '@aztec/foundation/branded-types';
4
+ import { Fr } from '@aztec/foundation/curves/bn254';
5
+ import type { LoggerBindings } from '@aztec/foundation/log';
6
+ import { type PromiseWithResolvers, promiseWithResolvers } from '@aztec/foundation/promise';
7
+ import type { Tuple } from '@aztec/foundation/serialize';
8
+ import type { EthAddress } from '@aztec/stdlib/block';
9
+ import type {
10
+ ForkMerkleTreeOperations,
11
+ PublicInputsAndRecursiveProof,
12
+ ReadonlyWorldStateAccess,
13
+ ServerCircuitProver,
14
+ } from '@aztec/stdlib/interfaces/server';
15
+ import type {
16
+ BlockRollupPublicInputs,
17
+ CheckpointConstantData,
18
+ PublicChonkVerifierPublicInputs,
19
+ } from '@aztec/stdlib/rollup';
20
+ import type { BlockHeader, Tx } from '@aztec/stdlib/tx';
21
+ import { type TelemetryClient, getTelemetryClient } from '@aztec/telemetry-client';
22
+
23
+ import { getPublicChonkVerifierPrivateInputsFromTx } from './block-building-helpers.js';
24
+ import type { BlockProvingState } from './block-proving-state.js';
25
+ import type { CheckpointProvingState } from './checkpoint-proving-state.js';
26
+ import type { EpochProvingContext } from './epoch-proving-context.js';
27
+ import { ProvingOrchestrator } from './orchestrator.js';
28
+
29
+ /**
30
+ * Result of proving a single checkpoint's block-level sub-tree.
31
+ *
32
+ * Contains the final block-rollup proof outputs that feed the checkpoint root rollup,
33
+ * plus the archive sibling path captured before any block in the checkpoint landed
34
+ * (the top-tree needs this to assemble the checkpoint root rollup hints).
35
+ */
36
+ export type SubTreeResult = {
37
+ blockProofOutputs: PublicInputsAndRecursiveProof<
38
+ BlockRollupPublicInputs,
39
+ typeof NESTED_RECURSIVE_ROLLUP_HONK_PROOF_LENGTH
40
+ >[];
41
+ previousArchiveSiblingPath: Tuple<Fr, typeof ARCHIVE_HEIGHT>;
42
+ };
43
+
44
+ /**
45
+ * Orchestrates block-level proving for a single checkpoint, stopping at the boundary
46
+ * where checkpoint root rollup would otherwise begin.
47
+ *
48
+ * Reuses every circuit driver in `ProvingOrchestrator` (chonk verifier, base, merge,
49
+ * block-root, parity, block-merge) but overrides the gating method that escalates to
50
+ * checkpoint root rollup. Instead of escalating, the orchestrator resolves
51
+ * `getSubTreeResult()` once every block-level proof in the checkpoint's tree is ready.
52
+ *
53
+ * Wiring: a single-checkpoint epoch is created in the constructor (epoch number sourced
54
+ * from the supplied `EpochProvingContext`). The canonical way to obtain a fully-started
55
+ * sub-tree is the `start` static factory, which also drives the single internal
56
+ * `startNewCheckpoint(0, ...)` call. The sub-tree never calls `finalizeEpochStructure`;
57
+ * the override of `checkAndEnqueueCheckpointRootRollup` resolves `getSubTreeResult` once
58
+ * block-level proving completes.
59
+ */
60
+ export class CheckpointSubTreeOrchestrator extends ProvingOrchestrator {
61
+ private readonly subTreeResult: PromiseWithResolvers<SubTreeResult>;
62
+
63
+ constructor(
64
+ dbProvider: ReadonlyWorldStateAccess & ForkMerkleTreeOperations,
65
+ prover: ServerCircuitProver,
66
+ proverId: EthAddress,
67
+ /**
68
+ * Per-epoch shared chonk-verifier proof cache. Every chonk-verifier proof started
69
+ * by this sub-tree lives on the context and survives the sub-tree's cancellation,
70
+ * so a tx whose original checkpoint is reorged out and re-appears in a replacement
71
+ * checkpoint reuses the cached proof. The context's `epochNumber` is the epoch
72
+ * this sub-tree proves into.
73
+ */
74
+ private readonly epochContext: EpochProvingContext,
75
+ cancelJobsOnStop: boolean = false,
76
+ enqueueConcurrency: number,
77
+ telemetryClient: TelemetryClient = getTelemetryClient(),
78
+ bindings?: LoggerBindings,
79
+ ) {
80
+ super(dbProvider, prover, proverId, cancelJobsOnStop, enqueueConcurrency, telemetryClient, bindings);
81
+
82
+ // Single-checkpoint mini-epoch by construction. The total/challenges supplied to
83
+ // `super.startNewEpoch` are never read, because the sub-tree overrides
84
+ // `checkAndEnqueueCheckpointRootRollup` to short-circuit before the parent's
85
+ // checkpoint-root / finalize machinery would consume them.
86
+ super.startNewEpoch(epochContext.epochNumber, 1, FinalBlobBatchingChallenges.empty());
87
+
88
+ this.subTreeResult = promiseWithResolvers<SubTreeResult>();
89
+ // Mark the rejection branch as observed so a `cancel()` or proving failure does not
90
+ // surface an unhandled rejection when no consumer awaits getSubTreeResult().
91
+ this.subTreeResult.promise.catch(() => {});
92
+
93
+ // If the parent's proving state ever rejects, surface the failure on the sub-tree promise.
94
+ void this.provingPromise!.then(result => {
95
+ if (result.status === 'failure') {
96
+ this.subTreeResult.reject(new Error(result.reason));
97
+ }
98
+ });
99
+ }
100
+
101
+ /**
102
+ * Constructs and starts a sub-tree for a single checkpoint. The returned sub-tree
103
+ * has had its single internal `startNewCheckpoint(0, ...)` driven; callers proceed
104
+ * directly to per-block `startNewBlock` / `addTxs` / `setBlockCompleted`.
105
+ *
106
+ * If the internal `startNewCheckpoint` rejects, the partially-constructed sub-tree
107
+ * is stopped before the error propagates, so no broker resources leak.
108
+ */
109
+ public static async start(
110
+ dbProvider: ReadonlyWorldStateAccess & ForkMerkleTreeOperations,
111
+ prover: ServerCircuitProver,
112
+ proverId: EthAddress,
113
+ epochContext: EpochProvingContext,
114
+ cancelJobsOnStop: boolean,
115
+ enqueueConcurrency: number,
116
+ checkpointConstants: CheckpointConstantData,
117
+ l1ToL2Messages: Fr[],
118
+ totalNumBlocks: number,
119
+ headerOfLastBlockInPreviousCheckpoint: BlockHeader,
120
+ telemetryClient: TelemetryClient = getTelemetryClient(),
121
+ bindings?: LoggerBindings,
122
+ ): Promise<CheckpointSubTreeOrchestrator> {
123
+ const subTree = new CheckpointSubTreeOrchestrator(
124
+ dbProvider,
125
+ prover,
126
+ proverId,
127
+ epochContext,
128
+ cancelJobsOnStop,
129
+ enqueueConcurrency,
130
+ telemetryClient,
131
+ bindings,
132
+ );
133
+ try {
134
+ await ProvingOrchestrator.prototype.startNewCheckpoint.call(
135
+ subTree,
136
+ 0,
137
+ checkpointConstants,
138
+ l1ToL2Messages,
139
+ totalNumBlocks,
140
+ headerOfLastBlockInPreviousCheckpoint,
141
+ );
142
+ return subTree;
143
+ } catch (err) {
144
+ await subTree.stop().catch(() => {});
145
+ throw err;
146
+ }
147
+ }
148
+
149
+ /** Returns a promise that resolves when block-level proving completes for the checkpoint. */
150
+ public getSubTreeResult(): Promise<SubTreeResult> {
151
+ return this.subTreeResult.promise;
152
+ }
153
+
154
+ /**
155
+ * The epoch is started in the constructor.
156
+ */
157
+ public override startNewEpoch(
158
+ _epochNumber: EpochNumber,
159
+ _totalNumCheckpoints: number,
160
+ _finalBlobBatchingChallenges: FinalBlobBatchingChallenges,
161
+ ): void {
162
+ throw new Error('CheckpointSubTreeOrchestrator starts its epoch in the constructor; do not call startNewEpoch.');
163
+ }
164
+
165
+ /**
166
+ * The single internal checkpoint is started by the `start` factory
167
+ */
168
+ public override startNewCheckpoint(
169
+ _checkpointIndex: number,
170
+ _constants: CheckpointConstantData,
171
+ _l1ToL2Messages: Fr[],
172
+ _totalNumBlocks: number,
173
+ _headerOfLastBlockInPreviousCheckpoint: BlockHeader,
174
+ ): Promise<void> {
175
+ return Promise.reject(
176
+ new Error(
177
+ 'CheckpointSubTreeOrchestrator drives its single checkpoint in `start`; do not call startNewCheckpoint.',
178
+ ),
179
+ );
180
+ }
181
+
182
+ /**
183
+ * Returns the archive sibling path captured at the internal `startNewCheckpoint`.
184
+ * Available synchronously once `start` has resolved, before block-level proving
185
+ * completes. The top-tree consumer uses this to assemble checkpoint root rollup hints
186
+ * up-front so checkpoint root proofs can pipeline against in-flight sub-tree proving.
187
+ */
188
+ public getPreviousArchiveSiblingPath(): Tuple<Fr, typeof ARCHIVE_HEIGHT> {
189
+ const checkpoint = this.provingState!.getCheckpointProvingState(0);
190
+ if (!checkpoint) {
191
+ throw new Error('Checkpoint not started; call CheckpointSubTreeOrchestrator.start first.');
192
+ }
193
+ return checkpoint.getLastArchiveSiblingPath();
194
+ }
195
+
196
+ /**
197
+ * Override the checkpoint-root boundary: instead of escalating to checkpoint root,
198
+ * resolve the sub-tree promise with the block-level proof outputs once they're all ready.
199
+ */
200
+ // eslint-disable-next-line require-await
201
+ protected override async checkAndEnqueueCheckpointRootRollup(provingState: CheckpointProvingState): Promise<void> {
202
+ const proofs = provingState.getSubTreeOutputProofs();
203
+ const nonEmpty = proofs.filter((p): p is NonNullable<typeof p> => !!p);
204
+ if (proofs.length !== nonEmpty.length) {
205
+ // Block merge tree not fully resolved yet — will be retried as more block proofs land.
206
+ return;
207
+ }
208
+
209
+ this.subTreeResult.resolve({
210
+ blockProofOutputs: nonEmpty,
211
+ previousArchiveSiblingPath: provingState.getLastArchiveSiblingPath(),
212
+ });
213
+ }
214
+
215
+ /**
216
+ * Kickstart chonk-verifier circuits via the shared `EpochProvingContext`. The context
217
+ * owns the broker job lifecycle, so the proof survives this sub-tree's `cancel()` —
218
+ * a tx that ends up in a replacement checkpoint after a reorg can pick the cached
219
+ * promise up and skip re-proving.
220
+ */
221
+ public override startChonkVerifierCircuits(txs: Tx[]): Promise<void> {
222
+ if (!this.provingState?.verifyState()) {
223
+ return Promise.reject(new Error('Sub-tree proving state is not active.'));
224
+ }
225
+ const publicTxs = txs.filter(tx => tx.data.forPublic);
226
+ for (const tx of publicTxs) {
227
+ const txHash = tx.getTxHash().toString();
228
+ const inputs = getPublicChonkVerifierPrivateInputsFromTx(tx, this.getProverId().toField());
229
+ // Fire and forget — getOrEnqueueChonkVerifier later picks up the cached promise
230
+ // when the tx is processed inside its block.
231
+ void this.epochContext.enqueue(txHash, inputs);
232
+ }
233
+ return Promise.resolve();
234
+ }
235
+
236
+ /**
237
+ * Route the tx's chonk-verifier dependency through the per-epoch context: read the
238
+ * cached promise (or enqueue if missing), then `.then(handleResult)` to progress to
239
+ * the base rollup once the proof lands.
240
+ */
241
+ protected override getOrEnqueueChonkVerifier(provingState: BlockProvingState, txIndex: number) {
242
+ if (!provingState.verifyState()) {
243
+ return;
244
+ }
245
+
246
+ const txProvingState = provingState.getTxProvingState(txIndex);
247
+ const txHash = txProvingState.processedTx.hash.toString();
248
+
249
+ const handleResult = (
250
+ result: PublicInputsAndRecursiveProof<
251
+ PublicChonkVerifierPublicInputs,
252
+ typeof NESTED_RECURSIVE_ROLLUP_HONK_PROOF_LENGTH
253
+ >,
254
+ ) => {
255
+ if (!provingState.verifyState()) {
256
+ return;
257
+ }
258
+ txProvingState.setPublicChonkVerifierProof(result);
259
+ this.checkAndEnqueueBaseRollup(provingState, txIndex);
260
+ };
261
+
262
+ let promise = this.epochContext.getCached(txHash);
263
+ if (!promise) {
264
+ promise = this.epochContext.enqueue(txHash, txProvingState.getPublicChonkVerifierPrivateInputs());
265
+ }
266
+ void promise.then(handleResult).catch(() => {
267
+ // The context self-cleans on rejection; a future call (replacement sub-tree
268
+ // for this tx) will see the miss and re-enqueue. No action needed here.
269
+ });
270
+ }
271
+ }