@aztec/prover-client 0.0.1-commit.b655e406 → 0.0.1-commit.fce3e4f

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 (104) hide show
  1. package/dest/block-factory/index.d.ts +1 -1
  2. package/dest/block-factory/light.d.ts +7 -7
  3. package/dest/block-factory/light.d.ts.map +1 -1
  4. package/dest/block-factory/light.js +36 -22
  5. package/dest/config.d.ts +1 -1
  6. package/dest/index.d.ts +1 -1
  7. package/dest/light/lightweight_checkpoint_builder.d.ts +28 -0
  8. package/dest/light/lightweight_checkpoint_builder.d.ts.map +1 -0
  9. package/dest/light/lightweight_checkpoint_builder.js +107 -0
  10. package/dest/mocks/fixtures.d.ts +1 -4
  11. package/dest/mocks/fixtures.d.ts.map +1 -1
  12. package/dest/mocks/fixtures.js +4 -14
  13. package/dest/mocks/test_context.d.ts +26 -45
  14. package/dest/mocks/test_context.d.ts.map +1 -1
  15. package/dest/mocks/test_context.js +98 -112
  16. package/dest/orchestrator/block-building-helpers.d.ts +15 -17
  17. package/dest/orchestrator/block-building-helpers.d.ts.map +1 -1
  18. package/dest/orchestrator/block-building-helpers.js +83 -109
  19. package/dest/orchestrator/block-proving-state.d.ts +13 -8
  20. package/dest/orchestrator/block-proving-state.d.ts.map +1 -1
  21. package/dest/orchestrator/block-proving-state.js +81 -20
  22. package/dest/orchestrator/checkpoint-proving-state.d.ts +4 -5
  23. package/dest/orchestrator/checkpoint-proving-state.d.ts.map +1 -1
  24. package/dest/orchestrator/checkpoint-proving-state.js +9 -12
  25. package/dest/orchestrator/epoch-proving-state.d.ts +6 -5
  26. package/dest/orchestrator/epoch-proving-state.d.ts.map +1 -1
  27. package/dest/orchestrator/epoch-proving-state.js +2 -2
  28. package/dest/orchestrator/index.d.ts +1 -1
  29. package/dest/orchestrator/orchestrator.d.ts +5 -5
  30. package/dest/orchestrator/orchestrator.d.ts.map +1 -1
  31. package/dest/orchestrator/orchestrator.js +19 -27
  32. package/dest/orchestrator/orchestrator_metrics.d.ts +1 -1
  33. package/dest/orchestrator/orchestrator_metrics.d.ts.map +1 -1
  34. package/dest/orchestrator/tx-proving-state.d.ts +1 -1
  35. package/dest/orchestrator/tx-proving-state.d.ts.map +1 -1
  36. package/dest/orchestrator/tx-proving-state.js +2 -11
  37. package/dest/prover-client/factory.d.ts +1 -1
  38. package/dest/prover-client/index.d.ts +1 -1
  39. package/dest/prover-client/prover-client.d.ts +1 -1
  40. package/dest/prover-client/prover-client.d.ts.map +1 -1
  41. package/dest/prover-client/server-epoch-prover.d.ts +5 -4
  42. package/dest/prover-client/server-epoch-prover.d.ts.map +1 -1
  43. package/dest/prover-client/server-epoch-prover.js +2 -2
  44. package/dest/proving_broker/broker_prover_facade.d.ts +20 -20
  45. package/dest/proving_broker/broker_prover_facade.d.ts.map +1 -1
  46. package/dest/proving_broker/broker_prover_facade.js +3 -2
  47. package/dest/proving_broker/config.d.ts +11 -7
  48. package/dest/proving_broker/config.d.ts.map +1 -1
  49. package/dest/proving_broker/config.js +7 -1
  50. package/dest/proving_broker/factory.d.ts +1 -1
  51. package/dest/proving_broker/fixtures.d.ts +3 -2
  52. package/dest/proving_broker/fixtures.d.ts.map +1 -1
  53. package/dest/proving_broker/fixtures.js +2 -1
  54. package/dest/proving_broker/index.d.ts +1 -1
  55. package/dest/proving_broker/proof_store/factory.d.ts +2 -2
  56. package/dest/proving_broker/proof_store/gcs_proof_store.d.ts +1 -1
  57. package/dest/proving_broker/proof_store/gcs_proof_store.d.ts.map +1 -1
  58. package/dest/proving_broker/proof_store/index.d.ts +1 -1
  59. package/dest/proving_broker/proof_store/inline_proof_store.d.ts +1 -1
  60. package/dest/proving_broker/proof_store/inline_proof_store.d.ts.map +1 -1
  61. package/dest/proving_broker/proof_store/proof_store.d.ts +1 -1
  62. package/dest/proving_broker/proving_agent.d.ts +1 -1
  63. package/dest/proving_broker/proving_agent.d.ts.map +1 -1
  64. package/dest/proving_broker/proving_agent_instrumentation.d.ts +1 -1
  65. package/dest/proving_broker/proving_agent_instrumentation.d.ts.map +1 -1
  66. package/dest/proving_broker/proving_broker.d.ts +2 -2
  67. package/dest/proving_broker/proving_broker.d.ts.map +1 -1
  68. package/dest/proving_broker/proving_broker.js +2 -1
  69. package/dest/proving_broker/proving_broker_database/memory.d.ts +3 -2
  70. package/dest/proving_broker/proving_broker_database/memory.d.ts.map +1 -1
  71. package/dest/proving_broker/proving_broker_database/persisted.d.ts +3 -2
  72. package/dest/proving_broker/proving_broker_database/persisted.d.ts.map +1 -1
  73. package/dest/proving_broker/proving_broker_database/persisted.js +3 -2
  74. package/dest/proving_broker/proving_broker_database.d.ts +3 -2
  75. package/dest/proving_broker/proving_broker_database.d.ts.map +1 -1
  76. package/dest/proving_broker/proving_broker_instrumentation.d.ts +1 -1
  77. package/dest/proving_broker/proving_broker_instrumentation.d.ts.map +1 -1
  78. package/dest/proving_broker/proving_job_controller.d.ts +3 -2
  79. package/dest/proving_broker/proving_job_controller.d.ts.map +1 -1
  80. package/dest/proving_broker/rpc.d.ts +4 -4
  81. package/dest/test/mock_proof_store.d.ts +3 -3
  82. package/dest/test/mock_proof_store.d.ts.map +1 -1
  83. package/dest/test/mock_prover.d.ts +3 -4
  84. package/dest/test/mock_prover.d.ts.map +1 -1
  85. package/package.json +18 -17
  86. package/src/block-factory/light.ts +39 -42
  87. package/src/light/lightweight_checkpoint_builder.ts +142 -0
  88. package/src/mocks/fixtures.ts +4 -27
  89. package/src/mocks/test_context.ts +140 -174
  90. package/src/orchestrator/block-building-helpers.ts +122 -203
  91. package/src/orchestrator/block-proving-state.ts +100 -23
  92. package/src/orchestrator/checkpoint-proving-state.ts +15 -13
  93. package/src/orchestrator/epoch-proving-state.ts +2 -3
  94. package/src/orchestrator/orchestrator.ts +23 -31
  95. package/src/orchestrator/tx-proving-state.ts +3 -16
  96. package/src/prover-client/server-epoch-prover.ts +3 -4
  97. package/src/proving_broker/broker_prover_facade.ts +21 -20
  98. package/src/proving_broker/config.ts +7 -0
  99. package/src/proving_broker/fixtures.ts +7 -2
  100. package/src/proving_broker/proving_broker.ts +2 -1
  101. package/src/proving_broker/proving_broker_database/memory.ts +2 -1
  102. package/src/proving_broker/proving_broker_database/persisted.ts +5 -4
  103. package/src/proving_broker/proving_broker_database.ts +2 -1
  104. package/src/proving_broker/proving_job_controller.ts +2 -1
@@ -1,8 +1,8 @@
1
1
  import {
2
- BatchedBlob,
3
2
  BatchedBlobAccumulator,
4
3
  SpongeBlob,
5
4
  computeBlobsHashFromBlobs,
5
+ encodeBlockBlobData,
6
6
  getBlobCommitmentsFromBlobs,
7
7
  getBlobsPerL1Block,
8
8
  } from '@aztec/blob-lib';
@@ -17,24 +17,17 @@ import {
17
17
  NULLIFIER_SUBTREE_HEIGHT,
18
18
  NULLIFIER_SUBTREE_ROOT_SIBLING_PATH_LENGTH,
19
19
  NULLIFIER_TREE_HEIGHT,
20
- NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP,
21
20
  PUBLIC_DATA_TREE_HEIGHT,
22
21
  } from '@aztec/constants';
23
22
  import { makeTuple } from '@aztec/foundation/array';
24
23
  import { padArrayEnd } from '@aztec/foundation/collection';
25
- import { sha256Trunc } from '@aztec/foundation/crypto';
26
24
  import { Fr } from '@aztec/foundation/fields';
27
- import { type Bufferable, type Tuple, assertLength, toFriendlyJSON } from '@aztec/foundation/serialize';
28
- import {
29
- MembershipWitness,
30
- MerkleTreeCalculator,
31
- computeCompressedUnbalancedMerkleTreeRoot,
32
- } from '@aztec/foundation/trees';
25
+ import { type Bufferable, assertLength, toFriendlyJSON } from '@aztec/foundation/serialize';
26
+ import { MembershipWitness } from '@aztec/foundation/trees';
33
27
  import { getVkData } from '@aztec/noir-protocol-circuits-types/server/vks';
34
28
  import { getVKIndex, getVKSiblingPath } from '@aztec/noir-protocol-circuits-types/vk-tree';
35
29
  import { computeFeePayerBalanceLeafSlot } from '@aztec/protocol-contracts/fee-juice';
36
- import { Body, L2BlockHeader, getBlockBlobFields } from '@aztec/stdlib/block';
37
- import { getCheckpointBlobFields } from '@aztec/stdlib/checkpoint';
30
+ import { Body } from '@aztec/stdlib/block';
38
31
  import type { MerkleTreeWriteOperations, PublicInputsAndRecursiveProof } from '@aztec/stdlib/interfaces/server';
39
32
  import { ContractClassLogFields } from '@aztec/stdlib/logs';
40
33
  import { Proof, ProofData, RecursiveProof } from '@aztec/stdlib/proofs';
@@ -50,13 +43,11 @@ import {
50
43
  AppendOnlyTreeSnapshot,
51
44
  MerkleTreeId,
52
45
  NullifierLeafPreimage,
53
- PublicDataTreeLeaf,
54
46
  PublicDataTreeLeafPreimage,
55
47
  getTreeHeight,
56
48
  } from '@aztec/stdlib/trees';
57
49
  import {
58
50
  BlockHeader,
59
- ContentCommitment,
60
51
  GlobalVariables,
61
52
  PartialStateReference,
62
53
  type ProcessedTx,
@@ -103,30 +94,7 @@ export const insertSideEffectsAndBuildBaseRollupHints = runInSpan(
103
94
  NOTE_HASH_SUBTREE_ROOT_SIBLING_PATH_LENGTH,
104
95
  );
105
96
 
106
- // Update the note hash trees with the new items being inserted to get the new roots
107
- // that will be used by the next iteration of the base rollup circuit, skipping the empty ones
108
- const noteHashes = padArrayEnd(tx.txEffect.noteHashes, Fr.ZERO, MAX_NOTE_HASHES_PER_TX);
109
- await db.appendLeaves(MerkleTreeId.NOTE_HASH_TREE, noteHashes);
110
-
111
- // The read witnesses for a given TX should be generated before the writes of the same TX are applied.
112
- // All reads that refer to writes in the same tx are transient and can be simplified out.
113
- const txPublicDataUpdateRequestInfo = await processPublicDataUpdateRequests(tx, db);
114
-
115
- // Update the nullifier tree, capturing the low nullifier info for each individual operation
116
- const {
117
- lowLeavesWitnessData: nullifierWitnessLeaves,
118
- newSubtreeSiblingPath: nullifiersSubtreeRootSiblingPath,
119
- sortedNewLeaves: sortedNullifiers,
120
- sortedNewLeavesIndexes,
121
- } = await db.batchInsert(
122
- MerkleTreeId.NULLIFIER_TREE,
123
- padArrayEnd(tx.txEffect.nullifiers, Fr.ZERO, MAX_NULLIFIERS_PER_TX).map(n => n.toBuffer()),
124
- NULLIFIER_SUBTREE_HEIGHT,
125
- );
126
-
127
- if (nullifierWitnessLeaves === undefined) {
128
- throw new Error(`Could not craft nullifier batch insertion proofs`);
129
- }
97
+ const { nullifierInsertionResult, publicDataInsertionResult } = await insertSideEffects(tx, db);
130
98
 
131
99
  const blockHash = await tx.data.constants.anchorBlockHeader.hash();
132
100
  const anchorBlockArchiveSiblingPath = (
@@ -146,52 +114,59 @@ export const insertSideEffectsAndBuildBaseRollupHints = runInSpan(
146
114
  contractClassLogsFields,
147
115
  });
148
116
  } else {
149
- if (
150
- txPublicDataUpdateRequestInfo.lowPublicDataWritesMembershipWitnesses.length > 1 ||
151
- txPublicDataUpdateRequestInfo.lowPublicDataWritesPreimages.length > 1 ||
152
- txPublicDataUpdateRequestInfo.publicDataWritesSiblingPaths.length > 1
153
- ) {
117
+ if (tx.txEffect.publicDataWrites.length > 1) {
154
118
  throw new Error(`More than one public data write in a private only tx`);
155
119
  }
156
120
 
157
121
  // Get hints for reading fee payer's balance in the public data tree.
158
- const feePayerBalanceMembershipWitness = txPublicDataUpdateRequestInfo.lowPublicDataWritesMembershipWitnesses[0];
159
- const feePayerBalanceLeafPreimage = txPublicDataUpdateRequestInfo.lowPublicDataWritesPreimages[0];
122
+ const feePayerBalanceLeafWitnessData = publicDataInsertionResult.lowLeavesWitnessData[0];
123
+ const feePayerBalanceMembershipWitness = MembershipWitness.fromBufferArray<typeof PUBLIC_DATA_TREE_HEIGHT>(
124
+ feePayerBalanceLeafWitnessData.index,
125
+ assertLength(feePayerBalanceLeafWitnessData.siblingPath.toBufferArray(), PUBLIC_DATA_TREE_HEIGHT),
126
+ );
127
+ const feePayerBalanceLeafPreimage = feePayerBalanceLeafWitnessData.leafPreimage as PublicDataTreeLeafPreimage;
160
128
  const leafSlot = await computeFeePayerBalanceLeafSlot(tx.data.feePayer);
161
- if (!feePayerBalanceMembershipWitness || !leafSlot.equals(feePayerBalanceLeafPreimage?.leaf.slot)) {
129
+ if (!leafSlot.equals(feePayerBalanceLeafPreimage.leaf.slot)) {
162
130
  throw new Error(`Cannot find the public data tree leaf for the fee payer's balance`);
163
131
  }
164
132
 
165
- // Extract witness objects from returned data
166
- const nullifierPredecessorMembershipWitnessesWithoutPadding: MembershipWitness<typeof NULLIFIER_TREE_HEIGHT>[] =
167
- nullifierWitnessLeaves.map(l =>
168
- MembershipWitness.fromBufferArray(
133
+ // Get hints for inserting the nullifiers.
134
+ const nullifierLowLeavesWitnessData = nullifierInsertionResult.lowLeavesWitnessData!;
135
+ const nullifierPredecessorPreimages = padArrayEnd(
136
+ nullifierLowLeavesWitnessData.map(l => l.leafPreimage as NullifierLeafPreimage),
137
+ NullifierLeafPreimage.empty(),
138
+ MAX_NULLIFIERS_PER_TX,
139
+ );
140
+ const nullifierPredecessorMembershipWitnesses = padArrayEnd(
141
+ nullifierLowLeavesWitnessData.map(l =>
142
+ MembershipWitness.fromBufferArray<typeof NULLIFIER_TREE_HEIGHT>(
169
143
  l.index,
170
144
  assertLength(l.siblingPath.toBufferArray(), NULLIFIER_TREE_HEIGHT),
171
145
  ),
172
- );
146
+ ),
147
+ makeEmptyMembershipWitness(NULLIFIER_TREE_HEIGHT),
148
+ MAX_NULLIFIERS_PER_TX,
149
+ );
150
+ const sortedNullifiers = assertLength(
151
+ nullifierInsertionResult.sortedNewLeaves.map(n => Fr.fromBuffer(n)),
152
+ MAX_NULLIFIERS_PER_TX,
153
+ );
154
+ const sortedNullifierIndexes = assertLength(
155
+ nullifierInsertionResult.sortedNewLeavesIndexes,
156
+ MAX_NULLIFIERS_PER_TX,
157
+ );
158
+ const nullifierSubtreeRootSiblingPath = assertLength(
159
+ nullifierInsertionResult.newSubtreeSiblingPath.toFields(),
160
+ NULLIFIER_SUBTREE_ROOT_SIBLING_PATH_LENGTH,
161
+ );
173
162
 
174
163
  const treeSnapshotDiffHints = TreeSnapshotDiffHints.from({
175
164
  noteHashSubtreeRootSiblingPath,
176
- nullifierPredecessorPreimages: padArrayEnd(
177
- nullifierWitnessLeaves.map(l => l.leafPreimage as NullifierLeafPreimage),
178
- NullifierLeafPreimage.empty(),
179
- MAX_NULLIFIERS_PER_TX,
180
- ),
181
- nullifierPredecessorMembershipWitnesses: makeTuple(MAX_NULLIFIERS_PER_TX, i =>
182
- i < nullifierPredecessorMembershipWitnessesWithoutPadding.length
183
- ? nullifierPredecessorMembershipWitnessesWithoutPadding[i]
184
- : makeEmptyMembershipWitness(NULLIFIER_TREE_HEIGHT),
185
- ),
186
- sortedNullifiers: assertLength(
187
- sortedNullifiers.map(n => Fr.fromBuffer(n)),
188
- MAX_NULLIFIERS_PER_TX,
189
- ),
190
- sortedNullifierIndexes: assertLength(sortedNewLeavesIndexes, MAX_NULLIFIERS_PER_TX),
191
- nullifierSubtreeRootSiblingPath: assertLength(
192
- nullifiersSubtreeRootSiblingPath.toFields(),
193
- NULLIFIER_SUBTREE_ROOT_SIBLING_PATH_LENGTH,
194
- ),
165
+ nullifierPredecessorPreimages,
166
+ nullifierPredecessorMembershipWitnesses,
167
+ sortedNullifiers,
168
+ sortedNullifierIndexes,
169
+ nullifierSubtreeRootSiblingPath,
195
170
  feePayerBalanceMembershipWitness,
196
171
  });
197
172
 
@@ -217,6 +192,44 @@ export const insertSideEffectsAndBuildBaseRollupHints = runInSpan(
217
192
  },
218
193
  );
219
194
 
195
+ export const insertSideEffects = runInSpan(
196
+ 'BlockBuilderHelpers',
197
+ 'buildBaseRollupHints',
198
+ async (span: Span, tx: ProcessedTx, db: MerkleTreeWriteOperations) => {
199
+ span.setAttribute(Attributes.TX_HASH, tx.hash.toString());
200
+
201
+ // Insert the note hashes. Padded with zeros to the max number of note hashes per tx.
202
+ const noteHashes = padArrayEnd(tx.txEffect.noteHashes, Fr.ZERO, MAX_NOTE_HASHES_PER_TX);
203
+ await db.appendLeaves(MerkleTreeId.NOTE_HASH_TREE, noteHashes);
204
+
205
+ // Insert the nullifiers. Padded with zeros to the max number of nullifiers per tx.
206
+ // Capturing the low nullifier info for each individual operation.
207
+ const nullifierInsertionResult = await db.batchInsert(
208
+ MerkleTreeId.NULLIFIER_TREE,
209
+ padArrayEnd(tx.txEffect.nullifiers, Fr.ZERO, MAX_NULLIFIERS_PER_TX).map(n => n.toBuffer()),
210
+ NULLIFIER_SUBTREE_HEIGHT,
211
+ );
212
+ if (nullifierInsertionResult.lowLeavesWitnessData === undefined) {
213
+ throw new Error(`Failed to batch insert nullifiers.`);
214
+ }
215
+
216
+ if (tx.txEffect.publicDataWrites.some(write => write.isEmpty())) {
217
+ throw new Error(`Empty public data write in tx: ${toFriendlyJSON(tx)}.`);
218
+ }
219
+ // Insert the public data writes sequentially. No need to pad them to the max array size.
220
+ // Capturing the low leaf info for each individual operation.
221
+ const publicDataInsertionResult = await db.sequentialInsert(
222
+ MerkleTreeId.PUBLIC_DATA_TREE,
223
+ tx.txEffect.publicDataWrites.map(write => write.toBuffer()),
224
+ );
225
+
226
+ return {
227
+ nullifierInsertionResult,
228
+ publicDataInsertionResult,
229
+ };
230
+ },
231
+ );
232
+
220
233
  export function getChonkProofFromTx(tx: Tx | ProcessedTx) {
221
234
  const publicInputs = tx.data.publicInputs().toFields();
222
235
 
@@ -246,24 +259,15 @@ export const buildBlobHints = (blobFields: Fr[]) => {
246
259
  return { blobCommitments, blobs, blobsHash };
247
260
  };
248
261
 
249
- // Build the data required to prove the txs in an epoch. Currently only used in tests. It assumes 1 block per checkpoint.
250
- export const buildBlobDataFromTxs = async (txsPerCheckpoint: ProcessedTx[][]) => {
251
- const blobFields = txsPerCheckpoint.map(txs => getCheckpointBlobFields([txs.map(tx => tx.txEffect)]));
252
- const finalBlobChallenges = await buildFinalBlobChallenges(blobFields);
253
- return { blobFieldsLengths: blobFields.map(fields => fields.length), finalBlobChallenges };
254
- };
255
-
256
262
  export const buildFinalBlobChallenges = async (blobFieldsPerCheckpoint: Fr[][]) => {
257
- const blobs = blobFieldsPerCheckpoint.map(blobFields => getBlobsPerL1Block(blobFields));
258
- return await BatchedBlob.precomputeBatchedBlobChallenges(blobs);
263
+ return await BatchedBlobAccumulator.precomputeBatchedBlobChallenges(blobFieldsPerCheckpoint);
259
264
  };
260
265
 
261
266
  export const accumulateBlobs = runInSpan(
262
267
  'BlockBuilderHelpers',
263
268
  'accumulateBlobs',
264
269
  async (_span: Span, blobFields: Fr[], startBlobAccumulator: BatchedBlobAccumulator) => {
265
- const blobs = getBlobsPerL1Block(blobFields);
266
- const endBlobAccumulator = await startBlobAccumulator.accumulateBlobs(blobs);
270
+ const endBlobAccumulator = await startBlobAccumulator.accumulateFields(blobFields);
267
271
  return endBlobAccumulator;
268
272
  },
269
273
  );
@@ -303,103 +307,60 @@ export const buildHeaderAndBodyFromTxs = runInSpan(
303
307
  async (
304
308
  span,
305
309
  txs: ProcessedTx[],
310
+ lastArchive: AppendOnlyTreeSnapshot,
311
+ endState: StateReference,
306
312
  globalVariables: GlobalVariables,
307
- l1ToL2Messages: Fr[],
308
- db: MerkleTreeReadOperations,
309
- startSpongeBlob?: SpongeBlob,
313
+ startSpongeBlob: SpongeBlob,
314
+ isFirstBlock: boolean,
310
315
  ) => {
311
316
  span.setAttribute(Attributes.BLOCK_NUMBER, globalVariables.blockNumber);
312
- const stateReference = new StateReference(
313
- await getTreeSnapshot(MerkleTreeId.L1_TO_L2_MESSAGE_TREE, db),
314
- new PartialStateReference(
315
- await getTreeSnapshot(MerkleTreeId.NOTE_HASH_TREE, db),
316
- await getTreeSnapshot(MerkleTreeId.NULLIFIER_TREE, db),
317
- await getTreeSnapshot(MerkleTreeId.PUBLIC_DATA_TREE, db),
318
- ),
319
- );
320
-
321
- const previousArchive = await getTreeSnapshot(MerkleTreeId.ARCHIVE, db);
322
317
 
323
318
  const txEffects = txs.map(tx => tx.txEffect);
324
319
  const body = new Body(txEffects);
325
320
 
326
- const txOutHashes = txEffects.map(tx => tx.txOutHash());
327
- const outHash = txOutHashes.length === 0 ? Fr.ZERO : new Fr(computeCompressedUnbalancedMerkleTreeRoot(txOutHashes));
328
-
329
- const parityShaRoot = await computeInHashFromL1ToL2Messages(l1ToL2Messages);
330
- const blockBlobFields = body.toBlobFields();
331
- // TODO(#17027): This only works when there's one block per checkpoint.
332
- const blobFields = [new Fr(blockBlobFields.length + 1)].concat(blockBlobFields);
333
- const blobsHash = computeBlobsHashFromBlobs(getBlobsPerL1Block(blobFields));
334
-
335
- const contentCommitment = new ContentCommitment(blobsHash, parityShaRoot, outHash);
336
-
337
- const fees = txEffects.reduce((acc, tx) => acc.add(tx.transactionFee), Fr.ZERO);
338
- const manaUsed = txs.reduce((acc, tx) => acc.add(new Fr(tx.gasUsed.billedGas.l2Gas)), Fr.ZERO);
321
+ const totalFees = txEffects.reduce((acc, tx) => acc.add(tx.transactionFee), Fr.ZERO);
322
+ const totalManaUsed = txs.reduce((acc, tx) => acc.add(new Fr(tx.gasUsed.billedGas.l2Gas)), Fr.ZERO);
323
+
324
+ const { l1ToL2MessageTree, partial } = endState;
325
+
326
+ const blockBlobFields = encodeBlockBlobData({
327
+ blockEndMarker: {
328
+ timestamp: globalVariables.timestamp,
329
+ blockNumber: globalVariables.blockNumber,
330
+ numTxs: txs.length,
331
+ },
332
+ blockEndStateField: {
333
+ l1ToL2MessageNextAvailableLeafIndex: l1ToL2MessageTree.nextAvailableLeafIndex,
334
+ noteHashNextAvailableLeafIndex: partial.noteHashTree.nextAvailableLeafIndex,
335
+ nullifierNextAvailableLeafIndex: partial.nullifierTree.nextAvailableLeafIndex,
336
+ publicDataNextAvailableLeafIndex: partial.publicDataTree.nextAvailableLeafIndex,
337
+ totalManaUsed: totalManaUsed.toBigInt(),
338
+ },
339
+ lastArchiveRoot: lastArchive.root,
340
+ noteHashRoot: partial.noteHashTree.root,
341
+ nullifierRoot: partial.nullifierTree.root,
342
+ publicDataRoot: partial.publicDataTree.root,
343
+ l1ToL2MessageRoot: isFirstBlock ? l1ToL2MessageTree.root : undefined,
344
+ txs: body.toTxBlobData(),
345
+ });
339
346
 
340
- const endSpongeBlob = startSpongeBlob?.clone() ?? (await SpongeBlob.init(blobFields.length));
347
+ const endSpongeBlob = startSpongeBlob.clone();
341
348
  await endSpongeBlob.absorb(blockBlobFields);
342
349
  const spongeBlobHash = await endSpongeBlob.squeeze();
343
350
 
344
- const header = new L2BlockHeader(
345
- previousArchive,
346
- contentCommitment,
347
- stateReference,
348
- globalVariables,
349
- fees,
350
- manaUsed,
351
+ const header = BlockHeader.from({
352
+ lastArchive,
353
+ state: endState,
351
354
  spongeBlobHash,
352
- );
353
-
354
- return { header, body };
355
- },
356
- );
357
-
358
- export const buildBlockHeaderFromTxs = runInSpan(
359
- 'BlockBuilderHelpers',
360
- 'buildBlockHeaderFromTxs',
361
- async (
362
- span,
363
- txs: ProcessedTx[],
364
- globalVariables: GlobalVariables,
365
- startSpongeBlob: SpongeBlob,
366
- db: MerkleTreeReadOperations,
367
- ) => {
368
- span.setAttribute(Attributes.BLOCK_NUMBER, globalVariables.blockNumber);
369
- const stateReference = new StateReference(
370
- await getTreeSnapshot(MerkleTreeId.L1_TO_L2_MESSAGE_TREE, db),
371
- new PartialStateReference(
372
- await getTreeSnapshot(MerkleTreeId.NOTE_HASH_TREE, db),
373
- await getTreeSnapshot(MerkleTreeId.NULLIFIER_TREE, db),
374
- await getTreeSnapshot(MerkleTreeId.PUBLIC_DATA_TREE, db),
375
- ),
376
- );
377
-
378
- const previousArchive = await getTreeSnapshot(MerkleTreeId.ARCHIVE, db);
379
-
380
- const blobFields = getBlockBlobFields(txs.map(tx => tx.txEffect));
381
- const endSpongeBlob = startSpongeBlob.clone();
382
- await endSpongeBlob.absorb(blobFields);
383
- const spongeBlobHash = await endSpongeBlob.squeeze();
384
-
385
- const txEffects = txs.map(tx => tx.txEffect);
386
- const fees = txEffects.reduce((acc, tx) => acc.add(tx.transactionFee), Fr.ZERO);
387
- const manaUsed = txs.reduce((acc, tx) => acc.add(new Fr(tx.gasUsed.billedGas.l2Gas)), Fr.ZERO);
355
+ globalVariables,
356
+ totalFees,
357
+ totalManaUsed,
358
+ });
388
359
 
389
- return new BlockHeader(previousArchive, stateReference, spongeBlobHash, globalVariables, fees, manaUsed);
360
+ return { header, body, blockBlobFields };
390
361
  },
391
362
  );
392
363
 
393
- /** Computes the inHash for a block's ContentCommitment given its l1 to l2 messages. */
394
- export async function computeInHashFromL1ToL2Messages(unpaddedL1ToL2Messages: Fr[]): Promise<Fr> {
395
- const l1ToL2Messages = padArrayEnd<Fr, number>(unpaddedL1ToL2Messages, Fr.ZERO, NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP);
396
- const hasher = (left: Buffer, right: Buffer) =>
397
- Promise.resolve(sha256Trunc(Buffer.concat([left, right])) as Buffer<ArrayBuffer>);
398
- const parityHeight = Math.ceil(Math.log2(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP));
399
- const parityCalculator = await MerkleTreeCalculator.create(parityHeight, Fr.ZERO.toBuffer(), hasher);
400
- return new Fr(await parityCalculator.computeTreeRoot(l1ToL2Messages.map(msg => msg.toBuffer())));
401
- }
402
-
403
364
  export async function getLastSiblingPath<TID extends MerkleTreeId>(treeId: TID, db: MerkleTreeReadOperations) {
404
365
  const { size } = await db.getTreeInfo(treeId);
405
366
  const path = await db.getSiblingPath(treeId, size - 1n);
@@ -425,48 +386,6 @@ export function makeEmptyMembershipWitness<N extends number>(height: N) {
425
386
  );
426
387
  }
427
388
 
428
- const processPublicDataUpdateRequests = runInSpan(
429
- 'BlockBuilderHelpers',
430
- 'processPublicDataUpdateRequests',
431
- async (span, tx: ProcessedTx, db: MerkleTreeWriteOperations) => {
432
- span.setAttribute(Attributes.TX_HASH, tx.hash.toString());
433
- const allPublicDataWrites = tx.txEffect.publicDataWrites.map(
434
- ({ leafSlot, value }) => new PublicDataTreeLeaf(leafSlot, value),
435
- );
436
-
437
- const { lowLeavesWitnessData, insertionWitnessData } = await db.sequentialInsert(
438
- MerkleTreeId.PUBLIC_DATA_TREE,
439
- allPublicDataWrites.map(write => {
440
- if (write.isEmpty()) {
441
- throw new Error(`Empty public data write in tx: ${toFriendlyJSON(tx)}`);
442
- }
443
- return write.toBuffer();
444
- }),
445
- );
446
-
447
- const lowPublicDataWritesPreimages = lowLeavesWitnessData.map(
448
- lowLeafWitness => lowLeafWitness.leafPreimage as PublicDataTreeLeafPreimage,
449
- );
450
- const lowPublicDataWritesMembershipWitnesses = lowLeavesWitnessData.map(lowLeafWitness =>
451
- MembershipWitness.fromBufferArray<typeof PUBLIC_DATA_TREE_HEIGHT>(
452
- lowLeafWitness.index,
453
- assertLength(lowLeafWitness.siblingPath.toBufferArray(), PUBLIC_DATA_TREE_HEIGHT),
454
- ),
455
- );
456
- const publicDataWritesSiblingPaths = insertionWitnessData.map(w => {
457
- const insertionSiblingPath = w.siblingPath.toFields();
458
- assertLength(insertionSiblingPath, PUBLIC_DATA_TREE_HEIGHT);
459
- return insertionSiblingPath as Tuple<Fr, typeof PUBLIC_DATA_TREE_HEIGHT>;
460
- });
461
-
462
- return {
463
- lowPublicDataWritesPreimages,
464
- lowPublicDataWritesMembershipWitnesses,
465
- publicDataWritesSiblingPaths,
466
- };
467
- },
468
- );
469
-
470
389
  export async function getSubtreeSiblingPath(
471
390
  treeId: MerkleTreeId,
472
391
  subtreeHeight: number,
@@ -1,4 +1,4 @@
1
- import type { SpongeBlob } from '@aztec/blob-lib';
1
+ import { type BlockBlobData, type BlockEndBlobData, type SpongeBlob, encodeBlockEndBlobData } from '@aztec/blob-lib';
2
2
  import {
3
3
  type ARCHIVE_HEIGHT,
4
4
  type L1_TO_L2_MSG_SUBTREE_ROOT_SIBLING_PATH_LENGTH,
@@ -25,7 +25,7 @@ import {
25
25
  } from '@aztec/stdlib/rollup';
26
26
  import type { CircuitName } from '@aztec/stdlib/stats';
27
27
  import { AppendOnlyTreeSnapshot } from '@aztec/stdlib/trees';
28
- import { type BlockHeader, GlobalVariables } from '@aztec/stdlib/tx';
28
+ import { BlockHeader, GlobalVariables, StateReference } from '@aztec/stdlib/tx';
29
29
  import type { UInt64 } from '@aztec/stdlib/types';
30
30
 
31
31
  import { buildHeaderFromCircuitOutputs, toProofData } from './block-building-helpers.js';
@@ -54,6 +54,7 @@ export class BlockProvingState {
54
54
  | ProofState<BlockRollupPublicInputs, typeof NESTED_RECURSIVE_ROLLUP_HONK_PROOF_LENGTH>
55
55
  | undefined;
56
56
  private builtBlockHeader: BlockHeader | undefined;
57
+ private endState: StateReference | undefined;
57
58
  private endSpongeBlob: SpongeBlob | undefined;
58
59
  private txs: TxProvingState[] = [];
59
60
  private isFirstBlock: boolean;
@@ -200,30 +201,34 @@ export class BlockProvingState {
200
201
  return this.blockRootProof?.provingOutput?.inputs;
201
202
  }
202
203
 
203
- public setBuiltBlockHeader(blockHeader: BlockHeader) {
204
- this.builtBlockHeader = blockHeader;
205
- }
204
+ public async buildBlockHeader() {
205
+ if (this.isAcceptingTxs()) {
206
+ throw new Error('All txs must be added to the block before building the header.');
207
+ }
208
+ if (!this.endState) {
209
+ throw new Error('Call `setEndState` first.');
210
+ }
211
+ if (!this.endSpongeBlob) {
212
+ throw new Error('Call `setEndSpongeBlob` first.');
213
+ }
214
+
215
+ const endSpongeBlob = this.endSpongeBlob.clone();
216
+ const endSpongeBlobHash = await endSpongeBlob.squeeze();
217
+
218
+ this.builtBlockHeader = new BlockHeader(
219
+ this.lastArchiveTreeSnapshot,
220
+ this.endState,
221
+ endSpongeBlobHash,
222
+ this.#getGlobalVariables(),
223
+ this.#getTotalFees(),
224
+ new Fr(this.#getTotalManaUsed()),
225
+ );
206
226
 
207
- public getBuiltBlockHeader() {
208
227
  return this.builtBlockHeader;
209
228
  }
210
229
 
211
- public getGlobalVariables() {
212
- if (this.txs.length) {
213
- return this.txs[0].processedTx.globalVariables;
214
- }
215
-
216
- const constants = this.constants;
217
- return GlobalVariables.from({
218
- chainId: constants.chainId,
219
- version: constants.version,
220
- blockNumber: this.blockNumber,
221
- slotNumber: constants.slotNumber,
222
- timestamp: this.timestamp,
223
- coinbase: constants.coinbase,
224
- feeRecipient: constants.feeRecipient,
225
- gasFees: constants.gasFees,
226
- });
230
+ public getBuiltBlockHeader() {
231
+ return this.builtBlockHeader;
227
232
  }
228
233
 
229
234
  public getStartSpongeBlob() {
@@ -238,6 +243,52 @@ export class BlockProvingState {
238
243
  return this.endSpongeBlob;
239
244
  }
240
245
 
246
+ public setEndState(endState: StateReference) {
247
+ this.endState = endState;
248
+ }
249
+
250
+ public hasEndState() {
251
+ return !!this.endState;
252
+ }
253
+
254
+ public getBlockEndBlobFields(): Fr[] {
255
+ return encodeBlockEndBlobData(this.getBlockEndBlobData());
256
+ }
257
+
258
+ getBlockEndBlobData(): BlockEndBlobData {
259
+ if (!this.endState) {
260
+ throw new Error('Call `setEndState` first.');
261
+ }
262
+
263
+ const partial = this.endState.partial;
264
+ return {
265
+ blockEndMarker: {
266
+ numTxs: this.totalNumTxs,
267
+ timestamp: this.timestamp,
268
+ blockNumber: this.blockNumber,
269
+ },
270
+ blockEndStateField: {
271
+ l1ToL2MessageNextAvailableLeafIndex: this.newL1ToL2MessageTreeSnapshot.nextAvailableLeafIndex,
272
+ noteHashNextAvailableLeafIndex: partial.noteHashTree.nextAvailableLeafIndex,
273
+ nullifierNextAvailableLeafIndex: partial.nullifierTree.nextAvailableLeafIndex,
274
+ publicDataNextAvailableLeafIndex: partial.publicDataTree.nextAvailableLeafIndex,
275
+ totalManaUsed: this.#getTotalManaUsed(),
276
+ },
277
+ lastArchiveRoot: this.lastArchiveTreeSnapshot.root,
278
+ noteHashRoot: partial.noteHashTree.root,
279
+ nullifierRoot: partial.nullifierTree.root,
280
+ publicDataRoot: partial.publicDataTree.root,
281
+ l1ToL2MessageRoot: this.isFirstBlock ? this.newL1ToL2MessageTreeSnapshot.root : undefined,
282
+ };
283
+ }
284
+
285
+ public getBlockBlobData(): BlockBlobData {
286
+ return {
287
+ ...this.getBlockEndBlobData(),
288
+ txs: this.getTxEffects().map(t => t.toTxBlobData()),
289
+ };
290
+ }
291
+
241
292
  public getTxEffects() {
242
293
  return this.txs.map(t => t.processedTx.txEffect);
243
294
  }
@@ -295,7 +346,6 @@ export class BlockProvingState {
295
346
  this.lastArchiveTreeSnapshot,
296
347
  this.headerOfLastBlockInPreviousCheckpoint.state,
297
348
  this.constants,
298
- this.startSpongeBlob,
299
349
  this.timestamp,
300
350
  this.lastL1ToL2MessageSubtreeRootSiblingPath,
301
351
  this.lastArchiveSiblingPath,
@@ -392,4 +442,31 @@ export class BlockProvingState {
392
442
  ? [this.baseOrMergeProofs.getNode(rootLocation)?.provingOutput]
393
443
  : this.baseOrMergeProofs.getChildren(rootLocation).map(c => c?.provingOutput);
394
444
  }
445
+
446
+ #getGlobalVariables() {
447
+ if (this.txs.length) {
448
+ return this.txs[0].processedTx.globalVariables;
449
+ }
450
+
451
+ const constants = this.constants;
452
+
453
+ return GlobalVariables.from({
454
+ chainId: constants.chainId,
455
+ version: constants.version,
456
+ blockNumber: this.blockNumber,
457
+ slotNumber: constants.slotNumber,
458
+ timestamp: this.timestamp,
459
+ coinbase: constants.coinbase,
460
+ feeRecipient: constants.feeRecipient,
461
+ gasFees: constants.gasFees,
462
+ });
463
+ }
464
+
465
+ #getTotalFees() {
466
+ return this.txs.reduce((acc, tx) => acc.add(tx.processedTx.txEffect.transactionFee), Fr.ZERO);
467
+ }
468
+
469
+ #getTotalManaUsed() {
470
+ return this.txs.reduce((acc, tx) => acc + BigInt(tx.processedTx.gasUsed.billedGas.l2Gas), 0n);
471
+ }
395
472
  }