diff --git a/l1-contracts/src/core/Decoder.sol b/l1-contracts/src/core/Decoder.sol index b1ee91420e8..9ba6ae6ab92 100644 --- a/l1-contracts/src/core/Decoder.sol +++ b/l1-contracts/src/core/Decoder.sol @@ -48,12 +48,15 @@ pragma solidity >=0.8.18; * | 0x1bc + x + y | 0x04 | len(newContracts) denoted z * | 0x1c0 + x + y | z | newContracts * | 0x1c0 + x + y + z | z | newContractData + * | 0x1c0 + x + y + z | 0x04 | len(l1ToL2Messages) denoted w + * | 0x1c4 + x + y + z | w | l1ToL2Messages * |--- |--- | --- * */ contract Decoder { uint256 internal constant COMMITMENTS_PER_KERNEL = 4; uint256 internal constant NULLIFIERS_PER_KERNEL = 4; + uint256 internal constant L1_TO_L2_MESSAGES_PER_ROLLUP = 16; /** * @notice Decodes the inputs and computes values to check state against @@ -63,6 +66,7 @@ contract Decoder { * @return newStateHash - The state hash expected after the execution. * @return publicInputHash - The hash of the public inputs */ + // TODO: temporarily to get this going, the l1ToL2Messages are included here function _decode(bytes calldata _l2Block) internal pure @@ -89,18 +93,23 @@ contract Decoder { function _computePublicInputsHash(bytes calldata _l2Block) internal pure returns (bytes32) { // Compute the public inputs hash uint256 size = 0x194 + 0x20; + // block header bytes memory temp = new bytes(size); assembly { calldatacopy(add(temp, 0x20), add(_l2Block.offset, 0x20), size) } - bytes32 diffRoot = _computeDiffRoot(_l2Block); + // Diff root + (bytes32 diffRoot, bytes32 l1ToL2messagesHash) = _computeDiffRoot(_l2Block); assembly { mstore(add(temp, add(0x20, 0x194)), diffRoot) + mstore(add(temp, add(0x20, 0x1a4)), l1ToL2messagesHash) } + return sha256(temp); } + /** * @notice Extract the L2 block number from the block * @param _l2Block - The L2 block calldata @@ -150,7 +159,7 @@ contract Decoder { * @param _l2Block - The L2 block calldata. * @return The root of the "diff" tree */ - function _computeDiffRoot(bytes calldata _l2Block) internal pure returns (bytes32) { + function _computeDiffRoot(bytes calldata _l2Block) internal pure returns (bytes32 _diffRoot, bytes32 _l1ToL2MessagesHash) { Vars memory vars; { uint256 commitmentCount; @@ -183,6 +192,8 @@ contract Decoder { 0x178 + (baseLeafs.length * 2 * (NULLIFIERS_PER_KERNEL + COMMITMENTS_PER_KERNEL) * 0x20); uint256 srcContractDataOffset = srcContractOffset + vars.contractCount * 0x20; + uint256 srcL1ToL2MessagesDataOffset = srcContractDataOffset + vars.contractCount * 0x40; + for (uint256 i = 0; i < baseLeafs.length; i++) { /** * Compute the leaf to insert. @@ -255,7 +266,17 @@ contract Decoder { baseLeafs[i] = sha256(baseLeaf); } - return _computeRoot(baseLeafs); + _diffRoot = _computeRoot(baseLeafs); + + // TODO: tidy this up + // TODO: calcualte the offset for the messages, might be easier to do in the compute diff root method as it gets all of that stuff + uint256 size = 0x20 * L1_TO_L2_MESSAGES_PER_ROLLUP; + bytes memory temp = new bytes(size); + assembly { + calldatacopy(add(temp, 0x20), add(srcL1ToL2MessagesDataOffset, 0x20), size) + } + _l1ToL2MessagesHash = sha256(temp); + } /** diff --git a/yarn-project/types/src/l2_block.ts b/yarn-project/types/src/l2_block.ts index 7492100984a..df9142a769f 100644 --- a/yarn-project/types/src/l2_block.ts +++ b/yarn-project/types/src/l2_block.ts @@ -3,6 +3,7 @@ import { KERNEL_NEW_COMMITMENTS_LENGTH, KERNEL_NEW_CONTRACTS_LENGTH, KERNEL_NEW_NULLIFIERS_LENGTH, + NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP, } from '@aztec/circuits.js'; import { makeAppendOnlyTreeSnapshot } from '@aztec/circuits.js/factories'; import { BufferReader, serializeToBuffer } from '@aztec/circuits.js/utils'; @@ -58,6 +59,7 @@ export class L2Block { public newNullifiers: Fr[], public newContracts: Fr[], public newContractData: ContractData[], + public newL1ToL2Messages: Fr[] = [], ) {} // TODO: do the newMessages need to be public inputs for stuff @@ -74,6 +76,9 @@ export class L2Block { const newContractsData = Array(KERNEL_NEW_CONTRACTS_LENGTH * txsPerBlock) .fill(0) .map(() => ContractData.random()); + const newL1ToL2Messages = Array(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP) + .fill(0) + .map(() => Fr.random()); return new L2Block( l2BlockNum, @@ -95,6 +100,7 @@ export class L2Block { newNullifiers, newContracts, newContractsData, + newL1ToL2Messages, ); } @@ -123,6 +129,7 @@ export class L2Block { newNullifiers: Fr[]; newContracts: Fr[]; newContractData: ContractData[]; + newL1ToL2Messages: Fr[]; }) { return new this( fields.number, @@ -144,6 +151,7 @@ export class L2Block { fields.newNullifiers, fields.newContracts, fields.newContractData, + fields.newL1ToL2Messages, ); } @@ -175,6 +183,7 @@ export class L2Block { this.newContracts.length, this.newContracts, this.newContractData, + this.newL1ToL2Messages, ); } @@ -212,6 +221,8 @@ export class L2Block { const newNullifiers = reader.readVector(Fr); const newContracts = reader.readVector(Fr); const newContractData = reader.readArray(newContracts.length, ContractData); + // could an optimisation of this be that it is encoded such that zeros are assumed + const newL1ToL2Messages = reader.readVector(Fr); return new L2Block( number, @@ -233,6 +244,7 @@ export class L2Block { newNullifiers, newContracts, newContractData, + newL1ToL2Messages, ); } @@ -321,6 +333,7 @@ export class L2Block { `newNullifiers: ${inspectFrArray(this.newNullifiers)}`, `newContracts: ${inspectFrArray(this.newContracts)}`, `newContractData: ${inspectContractDataArray(this.newContractData)}`, + `newL1ToL2Messages: ${inspectFrArray(this.newL1ToL2Messages)}`, ].join('\n'); } }