From 8eb5a77b5b68ec62c5018233fd0338b48dfb5c13 Mon Sep 17 00:00:00 2001 From: benesjan Date: Wed, 17 Jan 2024 15:36:01 +0000 Subject: [PATCH] HeaderLib --- l1-contracts/src/core/Rollup.sol | 37 ++----------- .../HeaderDecoder.sol => HeaderLib.sol} | 53 ++++++++++++++++--- l1-contracts/test/decoders/Decoder.t.sol | 4 +- .../decoders/helpers/HeaderDecoderHelper.sol | 6 +-- 4 files changed, 56 insertions(+), 44 deletions(-) rename l1-contracts/src/core/libraries/{decoders/HeaderDecoder.sol => HeaderLib.sol} (77%) diff --git a/l1-contracts/src/core/Rollup.sol b/l1-contracts/src/core/Rollup.sol index 6accbb836f54..fbced8300d8a 100644 --- a/l1-contracts/src/core/Rollup.sol +++ b/l1-contracts/src/core/Rollup.sol @@ -9,7 +9,7 @@ import {IOutbox} from "./interfaces/messagebridge/IOutbox.sol"; import {IRegistry} from "./interfaces/messagebridge/IRegistry.sol"; // Libraries -import {HeaderDecoder} from "./libraries/decoders/HeaderDecoder.sol"; +import {HeaderLib} from "./libraries/HeaderLib.sol"; import {MessagesDecoder} from "./libraries/decoders/MessagesDecoder.sol"; import {Hash} from "./libraries/Hash.sol"; import {Errors} from "./libraries/Errors.sol"; @@ -56,9 +56,9 @@ contract Rollup is IRollup { bytes calldata _body, // TODO(#3944): this will be replaced with _txsHash once the separation is finished. bytes memory _proof ) external override(IRollup) { - HeaderDecoder.Header memory header = HeaderDecoder.decode(_header); - - _validateHeader(header); + // Decode and validate header + HeaderLib.Header memory header = HeaderLib.decode(_header); + HeaderLib.validate(header, VERSION, lastBlockTs, archive); // Check if the data is available using availability oracle (change availability oracle if you want a different DA layer) bytes32 txsHash; @@ -99,35 +99,6 @@ contract Rollup is IRollup { emit L2BlockProcessed(header.globalVariables.blockNumber); } - function _validateHeader(HeaderDecoder.Header memory header) internal view { - if (block.chainid != header.globalVariables.chainId) { - revert Errors.Rollup__InvalidChainId(header.globalVariables.chainId, block.chainid); - } - - if (header.globalVariables.version != VERSION) { - revert Errors.Rollup__InvalidVersion(header.globalVariables.version, VERSION); - } - - // block number already constrained by archive root check - - if (header.globalVariables.timestamp > block.timestamp) { - revert Errors.Rollup__TimestampInFuture(); - } - - // @todo @LHerskind consider if this is too strict - // This will make multiple l2 blocks in the same l1 block impractical. - // e.g., the first block will update timestamp which will make the second fail. - // Could possibly allow multiple blocks if in same l1 block - if (header.globalVariables.timestamp < lastBlockTs) { - revert Errors.Rollup__TimestampTooOld(); - } - - // @todo @LHerskind Proper genesis state. If the state is empty, we allow anything for now. - if (archive != bytes32(0) && archive != header.lastArchive.root) { - revert Errors.Rollup__InvalidArchive(archive, header.lastArchive.root); - } - } - function _computePublicInputHash(bytes calldata _header, bytes32 _txsHash, bytes32 _inHash) internal pure diff --git a/l1-contracts/src/core/libraries/decoders/HeaderDecoder.sol b/l1-contracts/src/core/libraries/HeaderLib.sol similarity index 77% rename from l1-contracts/src/core/libraries/decoders/HeaderDecoder.sol rename to l1-contracts/src/core/libraries/HeaderLib.sol index 5839dca1462a..c6481f53ee01 100644 --- a/l1-contracts/src/core/libraries/decoders/HeaderDecoder.sol +++ b/l1-contracts/src/core/libraries/HeaderLib.sol @@ -3,13 +3,14 @@ pragma solidity >=0.8.18; // Libraries -import {Constants} from "../ConstantsGen.sol"; -import {Hash} from "../Hash.sol"; +import {Errors} from "./Errors.sol"; +import {Constants} from "./ConstantsGen.sol"; +import {Hash} from "./Hash.sol"; /** - * @title Header Decoder Library + * @title Header Library * @author Aztec Labs - * @notice Decoding a L2 header + * @notice Decoding and validating an L2 block header * Concerned with readability and velocity of development not giving a damn about gas costs. * * ------------------- @@ -47,7 +48,7 @@ import {Hash} from "../Hash.sol"; * | | | } * | --- | --- | --- */ -library HeaderDecoder { +library HeaderLib { struct AppendOnlyTreeSnapshot { bytes32 root; uint32 nextAvailableLeafIndex; @@ -82,7 +83,8 @@ library HeaderDecoder { /** * @notice Decodes the header - * @param _header - The header calldata. + * @param _header - The header calldata + * @return The decoded header */ function decode(bytes calldata _header) internal pure returns (Header memory) { require(_header.length == 376, "Invalid header length"); @@ -110,4 +112,43 @@ library HeaderDecoder { return header; } + + /** + * @notice Validates the header + * @param _header - The decoded header + * @param _version - The expected version + * @param _lastBlockTs - The timestamp of the last block + * @param _archive - The expected archive root + */ + function validate(Header memory _header, uint256 _version, uint256 _lastBlockTs, bytes32 _archive) + internal + view + { + if (block.chainid != _header.globalVariables.chainId) { + revert Errors.Rollup__InvalidChainId(_header.globalVariables.chainId, block.chainid); + } + + if (_header.globalVariables.version != _version) { + revert Errors.Rollup__InvalidVersion(_header.globalVariables.version, _version); + } + + // block number already constrained by archive root check + + if (_header.globalVariables.timestamp > block.timestamp) { + revert Errors.Rollup__TimestampInFuture(); + } + + // @todo @LHerskind consider if this is too strict + // This will make multiple l2 blocks in the same l1 block impractical. + // e.g., the first block will update timestamp which will make the second fail. + // Could possibly allow multiple blocks if in same l1 block + if (_header.globalVariables.timestamp < _lastBlockTs) { + revert Errors.Rollup__TimestampTooOld(); + } + + // @todo @LHerskind Proper genesis state. If the state is empty, we allow anything for now. + if (_archive != bytes32(0) && _archive != _header.lastArchive.root) { + revert Errors.Rollup__InvalidArchive(_archive, _header.lastArchive.root); + } + } } diff --git a/l1-contracts/test/decoders/Decoder.t.sol b/l1-contracts/test/decoders/Decoder.t.sol index 008b1494a4f2..e11586d30b43 100644 --- a/l1-contracts/test/decoders/Decoder.t.sol +++ b/l1-contracts/test/decoders/Decoder.t.sol @@ -11,9 +11,9 @@ import {DecoderHelper} from "./helpers/DecoderHelper.sol"; import {HeaderDecoderHelper} from "./helpers/HeaderDecoderHelper.sol"; import {MessagesDecoderHelper} from "./helpers/MessagesDecoderHelper.sol"; import {TxsDecoderHelper} from "./helpers/TxsDecoderHelper.sol"; +import {HeaderLib} from "../../src/core/libraries/HeaderLib.sol"; import {Decoder} from "../../src/core/libraries/decoders/Decoder.sol"; -import {HeaderDecoder} from "../../src/core/libraries/decoders/HeaderDecoder.sol"; import {MessagesDecoder} from "../../src/core/libraries/decoders/MessagesDecoder.sol"; import {TxsDecoder} from "../../src/core/libraries/decoders/TxsDecoder.sol"; @@ -59,7 +59,7 @@ contract DecoderTest is DecoderBase { // Header { DecoderBase.DecodedHeader memory referenceHeader = data.block.decodedHeader; - HeaderDecoder.Header memory header = headerHelper.decode(data.block.header); + HeaderLib.Header memory header = headerHelper.decode(data.block.header); // GlobalVariables { diff --git a/l1-contracts/test/decoders/helpers/HeaderDecoderHelper.sol b/l1-contracts/test/decoders/helpers/HeaderDecoderHelper.sol index 19908904c940..5d78b620b2a2 100644 --- a/l1-contracts/test/decoders/helpers/HeaderDecoderHelper.sol +++ b/l1-contracts/test/decoders/helpers/HeaderDecoderHelper.sol @@ -2,11 +2,11 @@ // Copyright 2023 Aztec Labs. pragma solidity >=0.8.18; -import {HeaderDecoder} from "../../../src/core/libraries/decoders/HeaderDecoder.sol"; +import {HeaderLib} from "../../../src/core/libraries/HeaderLib.sol"; contract HeaderDecoderHelper { // A wrapper used such that we get "calldata" and not memory - function decode(bytes calldata _header) public pure returns (HeaderDecoder.Header memory) { - return HeaderDecoder.decode(_header); + function decode(bytes calldata _header) public pure returns (HeaderLib.Header memory) { + return HeaderLib.decode(_header); } }