@@ -33,6 +33,7 @@ import {Leonidas} from "./sequencer_selection/Leonidas.sol";
33
33
contract Rollup is Leonidas , IRollup , ITestRollup {
34
34
struct BlockLog {
35
35
bytes32 archive;
36
+ bytes32 blockHash;
36
37
uint128 slotNumber;
37
38
bool isProven;
38
39
}
@@ -88,7 +89,8 @@ contract Rollup is Leonidas, IRollup, ITestRollup {
88
89
VERSION = 1 ;
89
90
90
91
// Genesis block
91
- blocks[0 ] = BlockLog ({archive: bytes32 (0 ), slotNumber: 0 , isProven: true });
92
+ blocks[0 ] =
93
+ BlockLog ({archive: bytes32 (0 ), blockHash: bytes32 (0 ), slotNumber: 0 , isProven: true });
92
94
pendingBlockCount = 1 ;
93
95
provenBlockCount = 1 ;
94
96
}
@@ -181,17 +183,19 @@ contract Rollup is Leonidas, IRollup, ITestRollup {
181
183
*
182
184
* @param _header - The L2 block header
183
185
* @param _archive - A root of the archive tree after the L2 block is applied
186
+ * @param _blockHash - The poseidon2 hash of the header added to the archive tree in the rollup circuit
184
187
* @param _signatures - Signatures from the validators
185
188
* @param _body - The body of the L2 block
186
189
*/
187
190
function publishAndProcess (
188
191
bytes calldata _header ,
189
192
bytes32 _archive ,
193
+ bytes32 _blockHash ,
190
194
SignatureLib.Signature[] memory _signatures ,
191
195
bytes calldata _body
192
196
) external override (IRollup) {
193
197
AVAILABILITY_ORACLE.publish (_body);
194
- process (_header, _archive, _signatures);
198
+ process (_header, _archive, _blockHash, _signatures);
195
199
}
196
200
197
201
/**
@@ -200,19 +204,24 @@ contract Rollup is Leonidas, IRollup, ITestRollup {
200
204
* @dev `eth_log_handlers` rely on this function
201
205
* @param _header - The L2 block header
202
206
* @param _archive - A root of the archive tree after the L2 block is applied
207
+ * @param _blockHash - The poseidon2 hash of the header added to the archive tree in the rollup circuit
203
208
* @param _body - The body of the L2 block
204
209
*/
205
- function publishAndProcess (bytes calldata _header , bytes32 _archive , bytes calldata _body )
206
- external
207
- override (IRollup)
208
- {
210
+ function publishAndProcess (
211
+ bytes calldata _header ,
212
+ bytes32 _archive ,
213
+ bytes32 _blockHash ,
214
+ bytes calldata _body
215
+ ) external override (IRollup) {
209
216
AVAILABILITY_ORACLE.publish (_body);
210
- process (_header, _archive);
217
+ process (_header, _archive, _blockHash );
211
218
}
212
219
213
220
/**
214
221
* @notice Submit a proof for a block in the pending chain
215
222
*
223
+ * @dev TODO(#7346): Verify root proofs rather than block root when batch rollups are integrated.
224
+ *
216
225
* @dev Will call `_progressState` to update the proven chain. Notice this have potentially
217
226
* unbounded gas consumption.
218
227
*
@@ -231,10 +240,11 @@ contract Rollup is Leonidas, IRollup, ITestRollup {
231
240
*
232
241
* @param _header - The header of the block (should match the block in the pending chain)
233
242
* @param _archive - The archive root of the block (should match the block in the pending chain)
243
+ * @param _proverId - The id of this block's prover
234
244
* @param _aggregationObject - The aggregation object for the proof
235
245
* @param _proof - The proof to verify
236
246
*/
237
- function submitProof (
247
+ function submitBlockRootProof (
238
248
bytes calldata _header ,
239
249
bytes32 _archive ,
240
250
bytes32 _proverId ,
@@ -259,23 +269,59 @@ contract Rollup is Leonidas, IRollup, ITestRollup {
259
269
revert Errors.Rollup__InvalidProposedArchive (expectedArchive, _archive);
260
270
}
261
271
262
- bytes32 [] memory publicInputs =
263
- new bytes32 [](4 + Constants.HEADER_LENGTH + Constants.AGGREGATION_OBJECT_LENGTH);
264
- // the archive tree root
265
- publicInputs[0 ] = _archive;
272
+ // TODO(#7346): Currently verifying block root proofs until batch rollups fully integrated.
273
+ // Hence the below pub inputs are BlockRootOrBlockMergePublicInputs, which are larger than
274
+ // the planned set (RootRollupPublicInputs), for the interim.
275
+ // Public inputs are not fully verified (TODO(#7373))
276
+
277
+ bytes32 [] memory publicInputs = new bytes32 [](
278
+ Constants.BLOCK_ROOT_OR_BLOCK_MERGE_PUBLIC_INPUTS_LENGTH + Constants.AGGREGATION_OBJECT_LENGTH
279
+ );
280
+
281
+ // From block_root_or_block_merge_public_inputs.nr: BlockRootOrBlockMergePublicInputs.
282
+ // previous_archive.root: the previous archive tree root
283
+ publicInputs[0 ] = expectedLastArchive;
284
+ // previous_archive.next_available_leaf_index: the previous archive next available index
285
+ publicInputs[1 ] = bytes32 (header.globalVariables.blockNumber);
286
+
287
+ // new_archive.root: the new archive tree root
288
+ publicInputs[2 ] = expectedArchive;
266
289
// this is the _next_ available leaf in the archive tree
267
290
// normally this should be equal to the block number (since leaves are 0-indexed and blocks 1-indexed)
268
291
// but in yarn-project/merkle-tree/src/new_tree.ts we prefill the tree so that block N is in leaf N
269
- publicInputs[1 ] = bytes32 (header.globalVariables.blockNumber + 1 );
270
-
271
- publicInputs[2 ] = vkTreeRoot;
272
-
273
- bytes32 [] memory headerFields = HeaderLib.toFields (header);
274
- for (uint256 i = 0 ; i < headerFields.length ; i++ ) {
275
- publicInputs[i + 3 ] = headerFields[i];
292
+ // new_archive.next_available_leaf_index: the new archive next available index
293
+ publicInputs[3 ] = bytes32 (header.globalVariables.blockNumber + 1 );
294
+
295
+ // TODO(#7346): Currently previous block hash is unchecked, but will be checked in batch rollup (block merge -> root).
296
+ // block-building-helpers.ts is injecting as 0 for now, replicating here.
297
+ // previous_block_hash: the block hash just preceding this block (will eventually become the end_block_hash of the prev batch)
298
+ publicInputs[4 ] = bytes32 (0 );
299
+
300
+ // end_block_hash: the current block hash (will eventually become the hash of the final block proven in a batch)
301
+ publicInputs[5 ] = blocks[header.globalVariables.blockNumber].blockHash;
302
+
303
+ // For block root proof outputs, we have a block 'range' of just 1 block => start and end globals are the same
304
+ bytes32 [] memory globalVariablesFields = HeaderLib.toFields (header.globalVariables);
305
+ for (uint256 i = 0 ; i < globalVariablesFields.length ; i++ ) {
306
+ // start_global_variables
307
+ publicInputs[i + 6 ] = globalVariablesFields[i];
308
+ // end_global_variables
309
+ publicInputs[globalVariablesFields.length + i + 6 ] = globalVariablesFields[i];
276
310
}
311
+ // out_hash: root of this block's l2 to l1 message tree (will eventually be root of roots)
312
+ publicInputs[24 ] = header.contentCommitment.outHash;
313
+
314
+ // For block root proof outputs, we have a single recipient-value fee payment pair,
315
+ // but the struct contains space for the max (32) => we keep 31*2=62 fields blank to represent it.
316
+ // fees: array of recipient-value pairs, for a single block just one entry (will eventually be filled and paid out here)
317
+ publicInputs[25 ] = bytes32 (uint256 (uint160 (header.globalVariables.coinbase)));
318
+ publicInputs[26 ] = bytes32 (header.totalFees);
319
+ // publicInputs[27] -> publicInputs[88] left blank for empty fee array entries
277
320
278
- publicInputs[headerFields.length + 3 ] = _proverId;
321
+ // vk_tree_root
322
+ publicInputs[89 ] = vkTreeRoot;
323
+ // prover_id: id of current block range's prover
324
+ publicInputs[90 ] = _proverId;
279
325
280
326
// the block proof is recursive, which means it comes with an aggregation object
281
327
// this snippet copies it into the public inputs needed for verification
@@ -286,7 +332,7 @@ contract Rollup is Leonidas, IRollup, ITestRollup {
286
332
assembly {
287
333
part := calldataload (add (_aggregationObject.offset, mul (i, 32 )))
288
334
}
289
- publicInputs[i + 4 + Constants.HEADER_LENGTH ] = part;
335
+ publicInputs[i + 91 ] = part;
290
336
}
291
337
292
338
if (! verifier.verify (_proof, publicInputs)) {
@@ -327,11 +373,13 @@ contract Rollup is Leonidas, IRollup, ITestRollup {
327
373
*
328
374
* @param _header - The L2 block header
329
375
* @param _archive - A root of the archive tree after the L2 block is applied
376
+ * @param _blockHash - The poseidon2 hash of the header added to the archive tree in the rollup circuit
330
377
* @param _signatures - Signatures from the validators
331
378
*/
332
379
function process (
333
380
bytes calldata _header ,
334
381
bytes32 _archive ,
382
+ bytes32 _blockHash ,
335
383
SignatureLib.Signature[] memory _signatures
336
384
) public override (IRollup) {
337
385
// Decode and validate header
@@ -343,6 +391,7 @@ contract Rollup is Leonidas, IRollup, ITestRollup {
343
391
// the slot number to uint128
344
392
blocks[pendingBlockCount++ ] = BlockLog ({
345
393
archive: _archive,
394
+ blockHash: _blockHash,
346
395
slotNumber: uint128 (header.globalVariables.slotNumber),
347
396
isProven: false
348
397
});
@@ -385,10 +434,14 @@ contract Rollup is Leonidas, IRollup, ITestRollup {
385
434
*
386
435
* @param _header - The L2 block header
387
436
* @param _archive - A root of the archive tree after the L2 block is applied
437
+ * @param _blockHash - The poseidon2 hash of the header added to the archive tree in the rollup circuit
388
438
*/
389
- function process (bytes calldata _header , bytes32 _archive ) public override (IRollup) {
439
+ function process (bytes calldata _header , bytes32 _archive , bytes32 _blockHash )
440
+ public
441
+ override (IRollup)
442
+ {
390
443
SignatureLib.Signature[] memory emptySignatures = new SignatureLib.Signature [](0 );
391
- process (_header, _archive, emptySignatures);
444
+ process (_header, _archive, _blockHash, emptySignatures);
392
445
}
393
446
394
447
/**
0 commit comments