Skip to content
Merged
1 change: 1 addition & 0 deletions l1-contracts/src/core/interfaces/IRollup.sol
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ struct SubmitEpochRootProofArgs {

struct BlockLog {
bytes32 archive;
bytes32 headerHash; // hash of the proposed block header
Slot slotNumber;
}

Expand Down
6 changes: 4 additions & 2 deletions l1-contracts/src/core/libraries/ConstantsGen.sol
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,8 @@ library Constants {
uint256 internal constant TOTAL_MANA_USED_LENGTH = 1;
uint256 internal constant BLOCK_HEADER_LENGTH = 25;
uint256 internal constant BLOCK_HEADER_LENGTH_BYTES = 648;
uint256 internal constant PROPOSED_BLOCK_HEADER_LENGTH = 12;
uint256 internal constant PROPOSED_BLOCK_HEADER_LENGTH_BYTES = 348;
uint256 internal constant PRIVATE_CIRCUIT_PUBLIC_INPUTS_LENGTH = 724;
uint256 internal constant PUBLIC_CIRCUIT_PUBLIC_INPUTS_LENGTH = 908;
uint256 internal constant PRIVATE_CONTEXT_INPUTS_LENGTH = 40;
Expand All @@ -214,8 +216,8 @@ library Constants {
uint256 internal constant PRIVATE_TO_ROLLUP_KERNEL_CIRCUIT_PUBLIC_INPUTS_LENGTH = 782;
uint256 internal constant CONSTANT_ROLLUP_DATA_LENGTH = 13;
uint256 internal constant BASE_OR_MERGE_PUBLIC_INPUTS_LENGTH = 52;
uint256 internal constant BLOCK_ROOT_OR_BLOCK_MERGE_PUBLIC_INPUTS_LENGTH = 984;
uint256 internal constant ROOT_ROLLUP_PUBLIC_INPUTS_LENGTH = 970;
uint256 internal constant BLOCK_ROOT_OR_BLOCK_MERGE_PUBLIC_INPUTS_LENGTH = 1032;
uint256 internal constant ROOT_ROLLUP_PUBLIC_INPUTS_LENGTH = 1020;
uint256 internal constant GET_NOTES_ORACLE_RETURN_LENGTH = 674;
uint256 internal constant NOTE_HASHES_NUM_BYTES_PER_BASE_ROLLUP = 2048;
uint256 internal constant NULLIFIERS_NUM_BYTES_PER_BASE_ROLLUP = 2048;
Expand Down
2 changes: 0 additions & 2 deletions l1-contracts/src/core/libraries/Errors.sol
Original file line number Diff line number Diff line change
Expand Up @@ -52,13 +52,11 @@ library Errors {
error Rollup__InsufficientFundsInEscrow(uint256 required, uint256 available); // 0xa165f276
error Rollup__InvalidArchive(bytes32 expected, bytes32 actual); // 0xb682a40e
error Rollup__InvalidBlockNumber(uint256 expected, uint256 actual); // 0xe5edf847
error Rollup__InvalidChainId(uint256 expected, uint256 actual); // 0x37b5bc12
error Rollup__InvalidInHash(bytes32 expected, bytes32 actual); // 0xcd6f4233
error Rollup__InvalidPreviousArchive(bytes32 expected, bytes32 actual); // 0xb682a40e
error Rollup__InvalidProof(); // 0xa5b2ba17
error Rollup__InvalidProposedArchive(bytes32 expected, bytes32 actual); // 0x32532e73
error Rollup__InvalidTimestamp(Timestamp expected, Timestamp actual); // 0x3132e895
error Rollup__InvalidVersion(uint256 expected, uint256 actual); // 0x9ef30794
error Rollup__InvalidBlobHash(bytes32 blobHash); // 0xc4a168c6
error Rollup__InvalidBlobProof(bytes32 blobHash); // 0x5ca17bef
error Rollup__InvalidBlobPublicInputsHash(bytes32 expected, bytes32 actual); // 0xfe6b4994
Expand Down
31 changes: 21 additions & 10 deletions l1-contracts/src/core/libraries/rollup/EpochProofLib.sol
Original file line number Diff line number Diff line change
Expand Up @@ -116,12 +116,6 @@ library EpochProofLib {
bytes calldata _blobPublicInputs
) internal view returns (bytes32[] memory) {
RollupStore storage rollupStore = STFLib.getStorage();
// Args are defined as an array because Solidity complains with "stack too deep" otherwise

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removing the comment as it's not an array anymore.

// 0 bytes32 _previousArchive,
// 1 bytes32 _endArchive,
// 2 bytes32 _endTimestamp,
// 3 bytes32 _outHash,
// 4 bytes32 _proverId,

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

Expand Down Expand Up @@ -154,7 +148,10 @@ library EpochProofLib {
// end_timestamp: u64,
// end_block_number: Field,
// out_hash: Field,
// proposedBlockHeaderHashes: [Field; Constants.AZTEC_MAX_EPOCH_DURATION],
// fees: [FeeRecipient; Constants.AZTEC_MAX_EPOCH_DURATION],
// chain_id: Field,
// version: Field,
// vk_tree_root: Field,
// protocol_contract_tree_root: Field,
// prover_id: Field,
Expand Down Expand Up @@ -185,12 +182,26 @@ library EpochProofLib {
publicInputs[6] = _args.outHash;
}

uint256 numBlocks = _end - _start + 1;

for (uint256 i = 0; i < numBlocks; i++) {
publicInputs[7 + i] = rollupStore.blocks[_start + i].headerHash;
}

uint256 offset = 7 + Constants.AZTEC_MAX_EPOCH_DURATION;

uint256 feesLength = Constants.AZTEC_MAX_EPOCH_DURATION * 2;
// fees[9 to (9+feesLength-1)]: array of recipient-value pairs
// fees[2n to 2n + 1]: a fee element, which contains of a recipient and a value
for (uint256 i = 0; i < feesLength; i++) {
publicInputs[7 + i] = _fees[i];
publicInputs[offset + i] = _fees[i];
}
uint256 offset = 7 + feesLength;
offset += feesLength;

publicInputs[offset] = bytes32(block.chainid);
offset += 1;

publicInputs[offset] = bytes32(rollupStore.config.version);
offset += 1;

// vk_tree_root
publicInputs[offset] = rollupStore.config.vkTreeRoot;
Expand All @@ -207,7 +218,7 @@ library EpochProofLib {
{
BlobVarsTemp memory tmp = BlobVarsTemp({blobOffset: 0, offset: offset, i: 0});
// blob_public_inputs
for (; tmp.i < _end - _start + 1; tmp.i++) {
for (; tmp.i < numBlocks; tmp.i++) {
uint8 blobsInBlock = uint8(_blobPublicInputs[tmp.blobOffset++]);
for (uint256 j = 0; j < Constants.BLOBS_PER_BLOCK; j++) {
if (j < blobsInBlock) {
Expand Down
142 changes: 39 additions & 103 deletions l1-contracts/src/core/libraries/rollup/HeaderLib.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,44 +3,16 @@
pragma solidity >=0.8.27;

import {Constants} from "@aztec/core/libraries/ConstantsGen.sol";
import {Hash} from "@aztec/core/libraries/crypto/Hash.sol";
import {Errors} from "@aztec/core/libraries/Errors.sol";

import {Slot, Timestamp} from "@aztec/core/libraries/TimeLib.sol";

struct AppendOnlyTreeSnapshot {
bytes32 root;
uint32 nextAvailableLeafIndex;
}

struct PartialStateReference {
AppendOnlyTreeSnapshot noteHashTree;
AppendOnlyTreeSnapshot nullifierTree;
AppendOnlyTreeSnapshot contractTree;
AppendOnlyTreeSnapshot publicDataTree;
}

struct StateReference {
AppendOnlyTreeSnapshot l1ToL2MessageTree;
// Note: Can't use "partial" name here as in protocol specs because it is a reserved solidity keyword
PartialStateReference partialStateReference;
}

struct GasFees {
uint256 feePerDaGas;
uint256 feePerL2Gas;
}

struct GlobalVariables {
uint256 chainId;
uint256 version;
uint256 blockNumber;
Slot slotNumber;
Timestamp timestamp;
address coinbase;
bytes32 feeRecipient;
GasFees gasFees;
}

struct ContentCommitment {
uint256 numTxs;
bytes32 blobsHash;
Expand All @@ -49,11 +21,13 @@ struct ContentCommitment {
}

struct Header {
AppendOnlyTreeSnapshot lastArchive;
bytes32 lastArchiveRoot;
ContentCommitment contentCommitment;
StateReference stateReference;
GlobalVariables globalVariables;
uint256 totalFees;
Slot slotNumber;
Timestamp timestamp;
address coinbase;
bytes32 feeRecipient;
GasFees gasFees;
uint256 totalManaUsed;
}

Expand All @@ -71,44 +45,24 @@ struct Header {
*
* | byte start | num bytes | name
* | --- | --- | ---
* | | | Header {
* | 0x0000 | 0x20 | lastArchive.root
* | 0x0020 | 0x04 | lastArchive.nextAvailableLeafIndex
* | | | ContentCommitment {
* | 0x0024 | 0x20 | numTxs
* | 0x0044 | 0x20 | blobsHash
* | 0x0064 | 0x20 | inHash
* | 0x0084 | 0x20 | outHash
* | | | StateReference {
* | 0x00a4 | 0x20 | l1ToL2MessageTree.root
* | 0x00c4 | 0x04 | l1ToL2MessageTree.nextAvailableLeafIndex
* | | | PartialStateReference {
* | 0x00c8 | 0x20 | noteHashTree.root
* | 0x00e8 | 0x04 | noteHashTree.nextAvailableLeafIndex
* | 0x00ec | 0x20 | nullifierTree.root
* | 0x010c | 0x04 | nullifierTree.nextAvailableLeafIndex
* | 0x0110 | 0x20 | publicDataTree.root
* | 0x0130 | 0x04 | publicDataTree.nextAvailableLeafIndex
* | | | }
* | | | }
* | | | GlobalVariables {
* | 0x0134 | 0x20 | chainId
* | 0x0154 | 0x20 | version
* | 0x0174 | 0x20 | blockNumber
* | 0x0194 | 0x20 | slotNumber
* | 0x01b4 | 0x20 | timestamp
* | 0x01d4 | 0x14 | coinbase
* | 0x01e8 | 0x20 | feeRecipient
* | 0x0208 | 0x20 | gasFees.feePerDaGas
* | 0x0228 | 0x20 | gasFees.feePerL2Gas
* | | | }
* | 0x0000 | 0x20 | lastArchiveRoot
* | | | ContentCommitment {
* | 0x0020 | 0x20 | numTxs
* | 0x0040 | 0x20 | blobsHash
* | 0x0060 | 0x20 | inHash
* | 0x0080 | 0x20 | outHash
* | | | }
* | 0x0248 | 0x20 | total_fees
* | 0x0268 | 0x20 | total_mana_used
* | 0x00a0 | 0x20 | slotNumber
* | 0x00c0 | 0x08 | timestamp
* | 0x00c8 | 0x14 | coinbase
* | 0x00dc | 0x20 | feeRecipient
* | 0x00fc | 0x20 | gasFees.feePerDaGas
* | 0x011c | 0x20 | gasFees.feePerL2Gas
* | 0x013c | 0x20 | totalManaUsed
* | --- | --- | ---
*/
library HeaderLib {
uint256 private constant HEADER_LENGTH = Constants.BLOCK_HEADER_LENGTH_BYTES; // Header byte length
uint256 private constant HEADER_LENGTH = Constants.PROPOSED_BLOCK_HEADER_LENGTH_BYTES; // Header byte length

/**
* @notice Decodes the header
Expand All @@ -124,47 +78,29 @@ library HeaderLib {
Header memory header;

// Reading lastArchive
header.lastArchive = AppendOnlyTreeSnapshot(
bytes32(_header[0x0000:0x0020]), uint32(bytes4(_header[0x0020:0x0024]))
);
header.lastArchiveRoot = bytes32(_header[0x0000:0x0020]);

// Reading ContentCommitment
header.contentCommitment.numTxs = uint256(bytes32(_header[0x0024:0x0044]));
header.contentCommitment.blobsHash = bytes32(_header[0x0044:0x0064]);
header.contentCommitment.inHash = bytes32(_header[0x0064:0x0084]);
header.contentCommitment.outHash = bytes32(_header[0x0084:0x00a4]);

// Reading StateReference
header.stateReference.l1ToL2MessageTree = AppendOnlyTreeSnapshot(
bytes32(_header[0x00a4:0x00c4]), uint32(bytes4(_header[0x00c4:0x00c8]))
);
header.stateReference.partialStateReference.noteHashTree = AppendOnlyTreeSnapshot(
bytes32(_header[0x00c8:0x00e8]), uint32(bytes4(_header[0x00e8:0x00ec]))
);
header.stateReference.partialStateReference.nullifierTree = AppendOnlyTreeSnapshot(
bytes32(_header[0x00ec:0x010c]), uint32(bytes4(_header[0x010c:0x0110]))
);
header.stateReference.partialStateReference.publicDataTree = AppendOnlyTreeSnapshot(
bytes32(_header[0x0110:0x0130]), uint32(bytes4(_header[0x0130:0x0134]))
);

// Reading GlobalVariables
header.globalVariables.chainId = uint256(bytes32(_header[0x0134:0x0154]));
header.globalVariables.version = uint256(bytes32(_header[0x0154:0x0174]));
header.globalVariables.blockNumber = uint256(bytes32(_header[0x0174:0x0194]));
header.globalVariables.slotNumber = Slot.wrap(uint256(bytes32(_header[0x0194:0x01b4])));
header.globalVariables.timestamp = Timestamp.wrap(uint256(bytes32(_header[0x01b4:0x01d4])));
header.globalVariables.coinbase = address(bytes20(_header[0x01d4:0x01e8]));
header.globalVariables.feeRecipient = bytes32(_header[0x01e8:0x0208]);
header.globalVariables.gasFees.feePerDaGas = uint256(bytes32(_header[0x0208:0x0228]));
header.globalVariables.gasFees.feePerL2Gas = uint256(bytes32(_header[0x0228:0x0248]));

// Reading totalFees
header.totalFees = uint256(bytes32(_header[0x0248:0x0268]));
header.contentCommitment.numTxs = uint256(bytes32(_header[0x0020:0x0040]));
header.contentCommitment.blobsHash = bytes32(_header[0x0040:0x0060]);
header.contentCommitment.inHash = bytes32(_header[0x0060:0x0080]);
header.contentCommitment.outHash = bytes32(_header[0x0080:0x00a0]);

// Reading partial GlobalVariables
header.slotNumber = Slot.wrap(uint256(bytes32(_header[0x00a0:0x00c0])));
header.timestamp = Timestamp.wrap(uint256(uint64(bytes8(_header[0x00c0:0x00c8]))));
header.coinbase = address(bytes20(_header[0x00c8:0x00dc]));
header.feeRecipient = bytes32(_header[0x00dc:0x00fc]);
header.gasFees.feePerDaGas = uint256(bytes32(_header[0x00fc:0x011c]));
header.gasFees.feePerL2Gas = uint256(bytes32(_header[0x011c:0x013c]));

// Reading totalManaUsed
header.totalManaUsed = uint256(bytes32(_header[0x0268:0x0288]));
header.totalManaUsed = uint256(bytes32(_header[0x013c:0x015c]));

return header;
}

function hash(bytes memory _header) internal pure returns (bytes32) {
return Hash.sha256ToField(_header);
}
}
Loading