Skip to content

Commit

Permalink
Decoding full header
Browse files Browse the repository at this point in the history
  • Loading branch information
benesjan committed Jan 16, 2024
1 parent 667331e commit 8206564
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 27 deletions.
21 changes: 10 additions & 11 deletions l1-contracts/src/core/Rollup.sol
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,9 @@ contract Rollup is IRollup {
function process(
bytes calldata _header,
bytes calldata _archive,
bytes calldata _body, // Note: this will be replaced with _txsHash once the separation is finished.
bytes calldata _body, // TODO(#3944): this will be replaced with _txsHash once the separation is finished.
bytes memory _proof
) external override(IRollup) {
// TODO: @benejsan Should we represent this values from header as a nice struct?
HeaderDecoder.Header memory header = HeaderDecoder.decode(_header);

_validateHeader(header);
Expand Down Expand Up @@ -96,35 +95,35 @@ contract Rollup is IRollup {
IOutbox outbox = REGISTRY.getOutbox();
outbox.sendL1Messages(l2ToL1Msgs);

emit L2BlockProcessed(header.blockNumber);
emit L2BlockProcessed(header.globalVariables.blockNumber);
}

function _validateHeader(HeaderDecoder.Header memory header) internal view {
if (block.chainid != header.chainId) {
revert Errors.Rollup__InvalidChainId(header.chainId, block.chainid);
if (block.chainid != header.globalVariables.chainId) {
revert Errors.Rollup__InvalidChainId(header.globalVariables.chainId, block.chainid);
}

if (header.version != VERSION) {
revert Errors.Rollup__InvalidVersion(header.version, VERSION);
if (header.globalVariables.version != VERSION) {
revert Errors.Rollup__InvalidVersion(header.globalVariables.version, VERSION);
}

// block number already constrained by archive hash check

if (header.timestamp > block.timestamp) {
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.timestamp < lastBlockTs) {
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) {
revert Errors.Rollup__InvalidArchive(archive, header.lastArchive);
if (archive != bytes32(0) && archive != header.lastArchiveRoot) {
revert Errors.Rollup__InvalidArchive(archive, header.lastArchiveRoot);
}
}

Expand Down
62 changes: 51 additions & 11 deletions l1-contracts/src/core/libraries/decoders/HeaderDecoder.sol
Original file line number Diff line number Diff line change
Expand Up @@ -48,30 +48,70 @@ import {Hash} from "../Hash.sol";
* | --- | --- | ---
*/
library HeaderDecoder {
// TODO: This is only partial
struct Header {
struct GlobalVariables {
uint256 chainId;
uint256 version;
uint256 blockNumber;
uint256 timestamp;
bytes32 lastArchive;
}

struct PartialStateReference {
bytes32 noteHashTreeRoot;
uint32 noteHashTreeNextAvailableLeafIndex;
bytes32 nullifierTreeRoot;
uint32 nullifierTreeNextAvailableLeafIndex;
bytes32 contractTreeRoot;
uint32 contractTreeNextAvailableLeafIndex;
bytes32 publicDataTreeRoot;
uint32 publicDataTreeNextAvailableLeafIndex;
}

struct StateReference {
bytes32 l1ToL2MessageTreeRoot;
uint32 l1ToL2MessageTreeNextAvailableLeafIndex;
// Note: Can't use "partial" name here as in yellow paper because it is a reserved solidity keyword
PartialStateReference partialStateReference;
}

struct Header {
GlobalVariables globalVariables;
StateReference stateReference;
bytes32 lastArchiveRoot;
uint32 lastArchiveNextAvailableLeafIndex;
bytes32 bodyHash;
}

/**
* @notice Decodes the header
* @param _header - The header calldata.
*/
function decode(bytes calldata _header) internal pure returns (Header memory) {
Header memory header;
require(_header.length == 376, "Invalid header length");

header.chainId = uint256(bytes32(_header[:0x20]));
header.version = uint256(bytes32(_header[0x20:0x40]));
header.blockNumber = uint256(bytes32(_header[0x40:0x60]));
header.timestamp = uint256(bytes32(_header[0x60:0x80]));

// The rest is needed only by verifier and hence not decoded here.
Header memory header;

header.lastArchive = bytes32(_header[0x134:0x154]);
header.globalVariables.chainId = uint256(bytes32(_header[:0x20]));
header.globalVariables.version = uint256(bytes32(_header[0x20:0x40]));
header.globalVariables.blockNumber = uint256(bytes32(_header[0x40:0x60]));
header.globalVariables.timestamp = uint256(bytes32(_header[0x60:0x80]));
header.stateReference.l1ToL2MessageTreeRoot = bytes32(_header[0x80:0xa0]);
header.stateReference.l1ToL2MessageTreeNextAvailableLeafIndex =
uint32(bytes4(_header[0xa0:0xa4]));
header.stateReference.partialStateReference.noteHashTreeRoot = bytes32(_header[0xa4:0xc4]);
header.stateReference.partialStateReference.noteHashTreeNextAvailableLeafIndex =
uint32(bytes4(_header[0xc4:0xc8]));
header.stateReference.partialStateReference.nullifierTreeRoot = bytes32(_header[0xc8:0xe8]);
header.stateReference.partialStateReference.nullifierTreeNextAvailableLeafIndex =
uint32(bytes4(_header[0xe8:0xec]));
header.stateReference.partialStateReference.contractTreeRoot = bytes32(_header[0xec:0x10c]);
header.stateReference.partialStateReference.contractTreeNextAvailableLeafIndex =
uint32(bytes4(_header[0x10c:0x110]));
header.stateReference.partialStateReference.publicDataTreeRoot = bytes32(_header[0x110:0x130]);
header.stateReference.partialStateReference.publicDataTreeNextAvailableLeafIndex =
uint32(bytes4(_header[0x130:0x134]));
header.lastArchiveRoot = bytes32(_header[0x134:0x154]);
header.lastArchiveNextAvailableLeafIndex = uint32(bytes4(_header[0x154:0x158]));
header.bodyHash = bytes32(_header[0x158:0x178]);

return header;
}
Expand Down
10 changes: 5 additions & 5 deletions l1-contracts/test/decoders/Decoder.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -60,11 +60,11 @@ contract DecoderTest is DecoderBase {
{
HeaderDecoder.Header memory header = headerHelper.decode(data.block.header);

assertEq(header.blockNumber, data.block.blockNumber, "Invalid block number");
assertEq(header.chainId, data.block.chainId, "Invalid chain Id");
assertEq(header.lastArchive, data.block.lastArchive, "Invalid last archive");
assertEq(header.timestamp, data.block.timestamp, "Invalid timestamp");
assertEq(header.version, data.block.version, "Invalid version");
assertEq(header.globalVariables.blockNumber, data.block.blockNumber, "Invalid block number");
assertEq(header.globalVariables.chainId, data.block.chainId, "Invalid chain Id");
assertEq(header.globalVariables.timestamp, data.block.timestamp, "Invalid timestamp");
assertEq(header.globalVariables.version, data.block.version, "Invalid version");
assertEq(header.lastArchiveRoot, data.block.lastArchive, "Invalid last archive");
}

// Messages
Expand Down

0 comments on commit 8206564

Please sign in to comment.