Skip to content

Commit f19c182

Browse files
authored
refactor: validate block header hash in circuits (#13094)
Previously: we computed the "end" block (header) hash in circuit and output it along with the previous block hash from block root. The L1 was supposed to check that the previous block hash was the same as the previous block's end block hash. But we only did that for the first block of the entire epoch, the rest of the proposed block hashes could be anything. Now: - Remove block hashes on l1, as it is committed to by archive roots. And nothing is looking up the block hash value on L1. - Constrain the previous block hash in block root rollup circuit by performing a membership check against the previous archive root.
1 parent 49ac1db commit f19c182

File tree

107 files changed

+2244
-2472
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

107 files changed

+2244
-2472
lines changed

l1-contracts/src/core/Rollup.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -285,7 +285,7 @@ contract Rollup is IStaking, IValidatorSelection, IRollup, RollupCore {
285285
*
286286
* @param _start - The start of the epoch (inclusive)
287287
* @param _end - The end of the epoch (inclusive)
288-
* @param _args - Array of public inputs to the proof (previousArchive, endArchive, previousBlockHash, endBlockHash, endTimestamp, outHash, proverId)
288+
* @param _args - Array of public inputs to the proof (previousArchive, endArchive, endTimestamp, outHash, proverId)
289289
* @param _fees - Array of recipient-value pairs with fees to be distributed for the epoch
290290
*/
291291
function getEpochProofPublicInputs(

l1-contracts/src/core/interfaces/IRollup.sol

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,6 @@ import {IERC20} from "@oz/token/ERC20/IERC20.sol";
1919
struct PublicInputArgs {
2020
bytes32 previousArchive;
2121
bytes32 endArchive;
22-
bytes32 previousBlockHash; // @todo #8829 Not needed as public input, unconstrained on L1
23-
bytes32 endBlockHash; // @todo #8829 Not needed as public input, unconstrained on L1
2422
Timestamp endTimestamp;
2523
bytes32 outHash;
2624
address proverId;
@@ -37,7 +35,6 @@ struct SubmitEpochRootProofArgs {
3735

3836
struct BlockLog {
3937
bytes32 archive;
40-
bytes32 blockHash;
4138
Slot slotNumber;
4239
}
4340

@@ -71,7 +68,6 @@ struct GenesisState {
7168
bytes32 vkTreeRoot;
7269
bytes32 protocolContractTreeRoot;
7370
bytes32 genesisArchiveRoot;
74-
bytes32 genesisBlockHash;
7571
}
7672

7773
struct RollupConfigInput {

l1-contracts/src/core/libraries/ConstantsGen.sol

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -96,8 +96,6 @@ library Constants {
9696
uint256 internal constant PUBLIC_LOG_SIZE_IN_FIELDS = 14;
9797
uint256 internal constant PRIVATE_LOG_SIZE_IN_FIELDS = 18;
9898
uint256 internal constant AZTEC_MAX_EPOCH_DURATION = 48;
99-
uint256 internal constant GENESIS_BLOCK_HASH =
100-
20646204262468251631976884937192820660867507115079672078981654411421834866549;
10199
uint256 internal constant GENESIS_ARCHIVE_ROOT =
102100
1002640778211850180189505934749257244705296832326768971348723156503780793518;
103101
uint256 internal constant PUBLIC_DISPATCH_SELECTOR = 3578010381;
@@ -216,8 +214,8 @@ library Constants {
216214
uint256 internal constant PRIVATE_TO_ROLLUP_KERNEL_CIRCUIT_PUBLIC_INPUTS_LENGTH = 782;
217215
uint256 internal constant CONSTANT_ROLLUP_DATA_LENGTH = 13;
218216
uint256 internal constant BASE_OR_MERGE_PUBLIC_INPUTS_LENGTH = 52;
219-
uint256 internal constant BLOCK_ROOT_OR_BLOCK_MERGE_PUBLIC_INPUTS_LENGTH = 986;
220-
uint256 internal constant ROOT_ROLLUP_PUBLIC_INPUTS_LENGTH = 972;
217+
uint256 internal constant BLOCK_ROOT_OR_BLOCK_MERGE_PUBLIC_INPUTS_LENGTH = 984;
218+
uint256 internal constant ROOT_ROLLUP_PUBLIC_INPUTS_LENGTH = 970;
221219
uint256 internal constant GET_NOTES_ORACLE_RETURN_LENGTH = 674;
222220
uint256 internal constant NOTE_HASHES_NUM_BYTES_PER_BASE_ROLLUP = 2048;
223221
uint256 internal constant NULLIFIERS_NUM_BYTES_PER_BASE_ROLLUP = 2048;

l1-contracts/src/core/libraries/Errors.sol

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,12 +51,10 @@ library Errors {
5151
error Rollup__InsufficientBondAmount(uint256 minimum, uint256 provided); // 0xa165f276
5252
error Rollup__InsufficientFundsInEscrow(uint256 required, uint256 available); // 0xa165f276
5353
error Rollup__InvalidArchive(bytes32 expected, bytes32 actual); // 0xb682a40e
54-
error Rollup__InvalidBlockHash(bytes32 expected, bytes32 actual);
5554
error Rollup__InvalidBlockNumber(uint256 expected, uint256 actual); // 0xe5edf847
5655
error Rollup__InvalidChainId(uint256 expected, uint256 actual); // 0x37b5bc12
5756
error Rollup__InvalidInHash(bytes32 expected, bytes32 actual); // 0xcd6f4233
5857
error Rollup__InvalidPreviousArchive(bytes32 expected, bytes32 actual); // 0xb682a40e
59-
error Rollup__InvalidPreviousBlockHash(bytes32 expected, bytes32 actual);
6058
error Rollup__InvalidProof(); // 0xa5b2ba17
6159
error Rollup__InvalidProposedArchive(bytes32 expected, bytes32 actual); // 0x32532e73
6260
error Rollup__InvalidTimestamp(Timestamp expected, Timestamp actual); // 0x3132e895

l1-contracts/src/core/libraries/rollup/EpochProofLib.sol

Lines changed: 12 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -68,12 +68,12 @@ library EpochProofLib {
6868
* - The archive root of the header does not match the archive root of the proposed block
6969
* - The proof is invalid
7070
*
71-
* @dev We provide the `_archive` and `_blockHash` even if it could be read from storage itself because it allow for
72-
* better error messages. Without passing it, we would just have a proof verification failure.
71+
* @dev We provide the `_archive` even if it could be read from storage itself because it allow for better error
72+
* messages. Without passing it, we would just have a proof verification failure.
7373
*
7474
* @param _args - The arguments to submit the epoch root proof:
7575
* _epochSize - The size of the epoch (to be promoted to a constant)
76-
* _args - Array of public inputs to the proof (previousArchive, endArchive, previousBlockHash, endBlockHash, endTimestamp, outHash, proverId)
76+
* _args - Array of public inputs to the proof (previousArchive, endArchive, endTimestamp, outHash, proverId)
7777
* _fees - Array of recipient-value pairs with fees to be distributed for the epoch
7878
* _blobPublicInputs - The blob public inputs for the proof
7979
* _proof - The proof to verify
@@ -104,7 +104,7 @@ library EpochProofLib {
104104
*
105105
* @param _start - The start of the epoch (inclusive)
106106
* @param _end - The end of the epoch (inclusive)
107-
* @param _args - Array of public inputs to the proof (previousArchive, endArchive, previousBlockHash, endBlockHash, endTimestamp, outHash, proverId)
107+
* @param _args - Array of public inputs to the proof (previousArchive, endArchive, endTimestamp, outHash, proverId)
108108
* @param _fees - Array of recipient-value pairs with fees to be distributed for the epoch
109109
* @param _blobPublicInputs- The blob public inputs for the proof
110110
*/
@@ -119,11 +119,9 @@ library EpochProofLib {
119119
// Args are defined as an array because Solidity complains with "stack too deep" otherwise
120120
// 0 bytes32 _previousArchive,
121121
// 1 bytes32 _endArchive,
122-
// 2 bytes32 _previousBlockHash,
123-
// 3 bytes32 _endBlockHash,
124-
// 4 bytes32 _endTimestamp,
125-
// 5 bytes32 _outHash,
126-
// 6 bytes32 _proverId,
122+
// 2 bytes32 _endTimestamp,
123+
// 3 bytes32 _outHash,
124+
// 4 bytes32 _proverId,
127125

128126
// TODO(#7373): Public inputs are not fully verified
129127

@@ -144,24 +142,6 @@ library EpochProofLib {
144142
Errors.Rollup__InvalidArchive(expectedEndArchive, _args.endArchive)
145143
);
146144
}
147-
148-
{
149-
bytes32 expectedPreviousBlockHash = rollupStore.blocks[_start - 1].blockHash;
150-
require(
151-
expectedPreviousBlockHash == _args.previousBlockHash,
152-
Errors.Rollup__InvalidPreviousBlockHash(
153-
expectedPreviousBlockHash, _args.previousBlockHash
154-
)
155-
);
156-
}
157-
158-
{
159-
bytes32 expectedEndBlockHash = rollupStore.blocks[_end].blockHash;
160-
require(
161-
expectedEndBlockHash == _args.endBlockHash,
162-
Errors.Rollup__InvalidBlockHash(expectedEndBlockHash, _args.endBlockHash)
163-
);
164-
}
165145
}
166146

167147
bytes32[] memory publicInputs = new bytes32[](Constants.ROOT_ROLLUP_PUBLIC_INPUTS_LENGTH);
@@ -171,8 +151,6 @@ library EpochProofLib {
171151
// struct RootRollupPublicInputs {
172152
// previous_archive: AppendOnlyTreeSnapshot,
173153
// end_archive: AppendOnlyTreeSnapshot,
174-
// previous_block_hash: Field,
175-
// end_block_hash: Field,
176154
// end_timestamp: u64,
177155
// end_block_number: Field,
178156
// out_hash: Field,
@@ -197,28 +175,22 @@ library EpochProofLib {
197175
// end_archive.next_available_leaf_index: the new archive next available index
198176
publicInputs[3] = bytes32(_end + 1);
199177

200-
// previous_block_hash: the block hash just preceding this epoch
201-
publicInputs[4] = _args.previousBlockHash;
202-
203-
// end_block_hash: the last block hash in the epoch
204-
publicInputs[5] = _args.endBlockHash;
205-
206178
// end_timestamp: the timestamp of the last block in the epoch
207-
publicInputs[6] = bytes32(Timestamp.unwrap(_args.endTimestamp));
179+
publicInputs[4] = bytes32(Timestamp.unwrap(_args.endTimestamp));
208180

209181
// end_block_number: last block number in the epoch
210-
publicInputs[7] = bytes32(_end);
182+
publicInputs[5] = bytes32(_end);
211183

212184
// out_hash: root of this epoch's l2 to l1 message tree
213-
publicInputs[8] = _args.outHash;
185+
publicInputs[6] = _args.outHash;
214186
}
215187

216188
uint256 feesLength = Constants.AZTEC_MAX_EPOCH_DURATION * 2;
217189
// fees[9 to (9+feesLength-1)]: array of recipient-value pairs
218190
for (uint256 i = 0; i < feesLength; i++) {
219-
publicInputs[9 + i] = _fees[i];
191+
publicInputs[7 + i] = _fees[i];
220192
}
221-
uint256 offset = 9 + feesLength;
193+
uint256 offset = 7 + feesLength;
222194

223195
// vk_tree_root
224196
publicInputs[offset] = rollupStore.config.vkTreeRoot;

l1-contracts/src/core/libraries/rollup/ProposeLib.sol

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ import {STFLib} from "./STFLib.sol";
2323

2424
struct ProposeArgs {
2525
bytes32 archive;
26-
bytes32 blockHash;
2726
OracleInput oracleInput;
2827
bytes header;
2928
bytes32[] txHashes;
@@ -107,11 +106,8 @@ library ProposeLib {
107106
RollupStore storage rollupStore = STFLib.getStorage();
108107
uint256 blockNumber = ++rollupStore.tips.pendingBlockNumber;
109108

110-
rollupStore.blocks[blockNumber] = BlockLog({
111-
archive: _args.archive,
112-
blockHash: _args.blockHash,
113-
slotNumber: header.globalVariables.slotNumber
114-
});
109+
rollupStore.blocks[blockNumber] =
110+
BlockLog({archive: _args.archive, slotNumber: header.globalVariables.slotNumber});
115111

116112
FeeLib.writeFeeHeader(
117113
blockNumber,

l1-contracts/src/core/libraries/rollup/STFLib.sol

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,8 @@ library STFLib {
2222
rollupStore.config.vkTreeRoot = _genesisState.vkTreeRoot;
2323
rollupStore.config.protocolContractTreeRoot = _genesisState.protocolContractTreeRoot;
2424

25-
rollupStore.blocks[0] = BlockLog({
26-
archive: _genesisState.genesisArchiveRoot,
27-
blockHash: _genesisState.genesisBlockHash,
28-
slotNumber: Slot.wrap(0)
29-
});
25+
rollupStore.blocks[0] =
26+
BlockLog({archive: _genesisState.genesisArchiveRoot, slotNumber: Slot.wrap(0)});
3027
}
3128

3229
function prune() internal {

0 commit comments

Comments
 (0)