Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: single tx block root rollup #11096

Merged
merged 9 commits into from
Jan 9, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions l1-contracts/foundry.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ remappings = [
fs_permissions = [
{access = "read", path = "./test/fixtures/mixed_block_1.json"},
{access = "read", path = "./test/fixtures/mixed_block_2.json"},
{access = "read", path = "./test/fixtures/single_tx_block_1.json"},
{access = "read", path = "./test/fixtures/single_tx_block_2.json"},
{access = "read", path = "./test/fixtures/empty_block_1.json"},
{access = "read", path = "./test/fixtures/empty_block_2.json"},
{access = "read", path = "./test/fixtures/fee_data_points.json"},
Expand Down
31 changes: 15 additions & 16 deletions l1-contracts/src/core/libraries/ConstantsGen.sol
Original file line number Diff line number Diff line change
Expand Up @@ -70,22 +70,21 @@ library Constants {
uint256 internal constant MAX_UNENCRYPTED_LOGS_PER_TX = 8;
uint256 internal constant MAX_CONTRACT_CLASS_LOGS_PER_TX = 1;
uint256 internal constant NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP = 16;
uint256 internal constant EMPTY_NESTED_INDEX = 0;
uint256 internal constant PRIVATE_KERNEL_EMPTY_INDEX = 1;
uint256 internal constant PRIVATE_KERNEL_INIT_INDEX = 2;
uint256 internal constant PRIVATE_KERNEL_INNER_INDEX = 3;
uint256 internal constant PRIVATE_KERNEL_TAIL_INDEX = 4;
uint256 internal constant PRIVATE_KERNEL_TAIL_TO_PUBLIC_INDEX = 5;
uint256 internal constant TUBE_VK_INDEX = 6;
uint256 internal constant PRIVATE_BASE_ROLLUP_VK_INDEX = 8;
uint256 internal constant PUBLIC_BASE_ROLLUP_VK_INDEX = 9;
uint256 internal constant BASE_PARITY_INDEX = 10;
uint256 internal constant ROOT_PARITY_INDEX = 11;
uint256 internal constant MERGE_ROLLUP_INDEX = 12;
uint256 internal constant BLOCK_ROOT_ROLLUP_INDEX = 13;
uint256 internal constant BLOCK_MERGE_ROLLUP_INDEX = 14;
uint256 internal constant ROOT_ROLLUP_INDEX = 15;
uint256 internal constant BLOCK_ROOT_ROLLUP_EMPTY_INDEX = 16;
uint256 internal constant PRIVATE_KERNEL_INIT_INDEX = 0;
uint256 internal constant PRIVATE_KERNEL_INNER_INDEX = 1;
uint256 internal constant PRIVATE_KERNEL_TAIL_INDEX = 2;
uint256 internal constant PRIVATE_KERNEL_TAIL_TO_PUBLIC_INDEX = 3;
uint256 internal constant TUBE_VK_INDEX = 4;
uint256 internal constant PRIVATE_BASE_ROLLUP_VK_INDEX = 6;
uint256 internal constant PUBLIC_BASE_ROLLUP_VK_INDEX = 7;
uint256 internal constant MERGE_ROLLUP_INDEX = 8;
uint256 internal constant BLOCK_ROOT_ROLLUP_INDEX = 9;
uint256 internal constant BLOCK_ROOT_ROLLUP_SINGLE_TX_INDEX = 10;
uint256 internal constant BLOCK_ROOT_ROLLUP_EMPTY_INDEX = 11;
uint256 internal constant BLOCK_MERGE_ROLLUP_INDEX = 12;
uint256 internal constant ROOT_ROLLUP_INDEX = 13;
uint256 internal constant BASE_PARITY_INDEX = 14;
uint256 internal constant ROOT_PARITY_INDEX = 15;
uint256 internal constant PRIVATE_KERNEL_RESET_INDEX = 20;
uint256 internal constant FUNCTION_SELECTOR_NUM_BYTES = 4;
uint256 internal constant INITIALIZATION_SLOT_SEPARATOR = 1000000000;
Expand Down
1 change: 0 additions & 1 deletion l1-contracts/src/core/libraries/Errors.sol
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ library Errors {
uint32 deadlinePassed
); // 0x5e789f34
error Outbox__InvalidPathLength(uint256 expected, uint256 actual); // 0x481bcd9c
error Outbox__InsertingInvalidRoot(); // 0x73c2daca
error Outbox__RootAlreadySetAtBlock(uint256 l2BlockNumber); // 0x3eccfd3e
error Outbox__InvalidRecipient(address expected, address actual); // 0x57aad581
error Outbox__AlreadyNullified(uint256 l2BlockNumber, uint256 leafIndex); // 0xfd71c2d4
Expand Down
13 changes: 8 additions & 5 deletions l1-contracts/src/core/libraries/crypto/MerkleLib.sol
Original file line number Diff line number Diff line change
Expand Up @@ -60,24 +60,27 @@ library MerkleLib {
* @return (min, max) - The min and max path sizes.
*/
function computeMinMaxPathLength(uint256 _numTxs) internal pure returns (uint256, uint256) {
uint256 numTxs = _numTxs < 2 ? 2 : _numTxs;
if (_numTxs < 2) {
return (0, 0);
}

uint256 numSubtrees = 0;
uint256 currentSubtreeSize = 1;
uint256 currentSubtreeHeight = 0;
uint256 firstSubtreeHeight;
uint256 finalSubtreeHeight;
while (numTxs != 0) {
while (_numTxs != 0) {
// If size & txs == 0, the subtree doesn't exist for this number of txs
if (currentSubtreeSize & numTxs == 0) {
if (currentSubtreeSize & _numTxs == 0) {
currentSubtreeSize <<= 1;
currentSubtreeHeight++;
continue;
}
// Assign the smallest rightmost subtree height
if (numSubtrees == 0) finalSubtreeHeight = currentSubtreeHeight;
// Assign the largest leftmost subtree height
if (numTxs - currentSubtreeSize == 0) firstSubtreeHeight = currentSubtreeHeight;
numTxs -= currentSubtreeSize;
if (_numTxs - currentSubtreeSize == 0) firstSubtreeHeight = currentSubtreeHeight;
_numTxs -= currentSubtreeSize;
currentSubtreeSize <<= 1;
currentSubtreeHeight++;
numSubtrees++;
Expand Down
1 change: 0 additions & 1 deletion l1-contracts/src/core/messagebridge/Outbox.sol
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@ contract Outbox is IOutbox {
override(IOutbox)
{
require(msg.sender == address(ROLLUP), Errors.Outbox__Unauthorized());
require(_root != bytes32(0), Errors.Outbox__InsertingInvalidRoot());
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Removing this check as we allow submitting an empty block, which will have 0 out hash.


roots[_l2BlockNumber].root = _root;
roots[_l2BlockNumber].minHeight = _minHeight;
Expand Down
8 changes: 0 additions & 8 deletions l1-contracts/test/Outbox.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -67,14 +67,6 @@ contract OutboxTest is Test {
outbox.insert(1, root, DEFAULT_TREE_HEIGHT);
}

function testRevertIfInsertingEmptyRoot() public {
bytes32 root = bytes32(0);

vm.prank(ROLLUP_CONTRACT);
vm.expectRevert(abi.encodeWithSelector(Errors.Outbox__InsertingInvalidRoot.selector));
outbox.insert(1, root, DEFAULT_TREE_HEIGHT);
}

// This function tests the insertion of random arrays of L2 to L1 messages
// We make a naive tree with a computed height, insert the leafs into it, and compute a root. We then add the root as the root of the
// L2 to L1 message tree, expect for the correct event to be emitted, and then query for the root in the contract—making sure the roots, as well as the
Expand Down
31 changes: 25 additions & 6 deletions l1-contracts/test/Rollup.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -626,10 +626,8 @@ contract RollupTest is DecoderBase, TimeFns {
uint256 minHeightEmpty =
uint256(vm.load(address(outbox), bytes32(uint256(keccak256(abi.encode(1, 0))) + 1)));

assertNotEq(rootEmpty, bytes32(0), "Invalid root");
assertEq(rootEmpty, bytes32(0), "Invalid root");
assertNotEq(minHeightEmpty, 0, "Invalid min height");
assertNotEq(rootEmpty, rootMixed, "Invalid root");
assertNotEq(minHeightEmpty, minHeightMixed, "Invalid min height");
}

function testShouldNotBeTooEagerToPrune() public setUpFor("mixed_block_1") {
Expand Down Expand Up @@ -841,6 +839,26 @@ contract RollupTest is DecoderBase, TimeFns {
assertEq(rollup.getProvenBlockNumber(), 0 + toProve, "Invalid proven block number");
}

function testSingleBlock(bool _toProve) public setUpFor("single_tx_block_1") {
_testBlock("single_tx_block_1", _toProve);

assertEq(rollup.getPendingBlockNumber(), 1, "Invalid pending block number");
assertEq(rollup.getProvenBlockNumber(), _toProve ? 1 : 0, "Invalid proven block number");
}

function testConsecutiveSingleTxBlocks(uint256 _blocksToProve)
public
setUpFor("single_tx_block_1")
{
uint256 toProve = bound(_blocksToProve, 0, 2);

_testBlock("single_tx_block_1", toProve > 0);
_testBlock("single_tx_block_2", toProve > 1);

assertEq(rollup.getPendingBlockNumber(), 2, "Invalid pending block number");
assertEq(rollup.getProvenBlockNumber(), 0 + toProve, "Invalid proven block number");
}

function testRevertSubmittingProofForBlocksAcrossEpochs() public setUpFor("mixed_block_1") {
_testBlock("mixed_block_1", false, 1);
_testBlock("mixed_block_2", false, TestConstants.AZTEC_EPOCH_DURATION + 1);
Expand Down Expand Up @@ -1275,19 +1293,20 @@ contract RollupTest is DecoderBase, TimeFns {
}

bytes32 l2ToL1MessageTreeRoot;
{
uint32 numTxs = full.block.numTxs;
if (numTxs != 0) {
// NB: The below works with full blocks because we require the largest possible subtrees
// for L2 to L1 messages - usually we make variable height subtrees, the roots of which
// form a balanced tree

// The below is a little janky - we know that this test deals with full txs with equal numbers
// of msgs or txs with no messages, so the division works
// TODO edit full.messages to include information about msgs per tx?
uint32 numTxs = full.block.numTxs;
uint256 subTreeHeight = full.messages.l2ToL1Messages.length == 0
? 0
: merkleTestUtil.calculateTreeHeightFromSize(full.messages.l2ToL1Messages.length / numTxs);
uint256 outHashTreeHeight = merkleTestUtil.calculateTreeHeightFromSize(numTxs);
uint256 outHashTreeHeight =
numTxs == 1 ? 0 : merkleTestUtil.calculateTreeHeightFromSize(numTxs);
uint256 numMessagesWithPadding = numTxs * Constants.MAX_L2_TO_L1_MSGS_PER_TX;

uint256 treeHeight = subTreeHeight + outHashTreeHeight;
Expand Down
47 changes: 32 additions & 15 deletions l1-contracts/test/fixtures/empty_block_1.json
Original file line number Diff line number Diff line change
@@ -1,34 +1,51 @@
{
"populate": {
"l1ToL2Content": [],
"recipient": "0x0000000000000000000000000000000000000000000000000000000000000000",
"l1ToL2Content": [
"0x0000000000000000000000000000000000000000000000000000000000000401",
"0x0000000000000000000000000000000000000000000000000000000000000402",
"0x0000000000000000000000000000000000000000000000000000000000000403",
"0x0000000000000000000000000000000000000000000000000000000000000404",
"0x0000000000000000000000000000000000000000000000000000000000000405",
"0x0000000000000000000000000000000000000000000000000000000000000406",
"0x0000000000000000000000000000000000000000000000000000000000000407",
"0x0000000000000000000000000000000000000000000000000000000000000408",
"0x0000000000000000000000000000000000000000000000000000000000000409",
"0x000000000000000000000000000000000000000000000000000000000000040a",
"0x000000000000000000000000000000000000000000000000000000000000040b",
"0x000000000000000000000000000000000000000000000000000000000000040c",
"0x000000000000000000000000000000000000000000000000000000000000040d",
"0x000000000000000000000000000000000000000000000000000000000000040e",
"0x000000000000000000000000000000000000000000000000000000000000040f",
"0x0000000000000000000000000000000000000000000000000000000000000410"
],
"recipient": "0x1647b194c649f5dd01d7c832f89b0f496043c9150797923ea89e93d5ac619a93",
"sender": "0x9965507D1a55bcC2695C58ba16FB37d819B0A4dc"
},
"messages": {
"l2ToL1Messages": []
},
"block": {
"archive": "0x2e558c94bd1a3d8512eaf74c297f8a5b28ca14c79636a9f81e0538804b21ff6c",
"blockHash": "0x20e7264407d9dad46301cd1ac2720619fa899e0dc07e2aeaaf1f58a9fe0d9b42",
"archive": "0x19d282bf5387d54a21db424a09ee23196be74da0dfbb4ca28a4939020da2adc4",
"blockHash": "0x0d03dd1cec142b914011e7ebf5375295b8ae9cec88accfb41b6bcbc5cb2e74f1",
"body": "0x00000000",
"decodedHeader": {
"contentCommitment": {
"blobsHash": "0x001cedbd7ea5309ef9d1d159209835409bf41b6b1802597a52fa70cc82e934d9",
"inHash": "0x00089a9d421a82c4a25f7acbebe69e638d5b064fa8a60e018793dcb0be53752c",
"outHash": "0x00f5a5fd42d16a20302798ef6ed309979b43003d2320d9f0e8ea9831a92759fb",
"numTxs": 2
"outHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"numTxs": 0
},
"globalVariables": {
"blockNumber": 1,
"slotNumber": "0x0000000000000000000000000000000000000000000000000000000000000012",
"slotNumber": "0x000000000000000000000000000000000000000000000000000000000000001b",
"chainId": 31337,
"timestamp": 1732961424,
"timestamp": 1736363020,
"version": 1,
"coinbase": "0x2cf4a1c62581a88edae4234f887da6b9551ab171",
"feeRecipient": "0x0339e43debc9c5093c6862f6dea7ff66fcd7f45c01f87dfa61f802d30530ea4e",
"coinbase": "0xb3402d01fb3d2005f49fa063cc2470cd3dcd8cee",
"feeRecipient": "0x1e5f75a4eff0236113040956df38e3ec6b175c9a46e289972a69ffb812506b21",
"gasFees": {
"feePerDaGas": 0,
"feePerL2Gas": 54153588500
"feePerL2Gas": 54153579570
}
},
"totalFees": "0x0000000000000000000000000000000000000000000000000000000000000000",
Expand All @@ -44,11 +61,11 @@
},
"partialStateReference": {
"noteHashTree": {
"nextAvailableLeafIndex": 128,
"nextAvailableLeafIndex": 0,
"root": "0x1fd848aa69e1633722fe249a5b7f53b094f1c9cef9f5c694b073fd1cc5850dfb"
},
"nullifierTree": {
"nextAvailableLeafIndex": 256,
"nextAvailableLeafIndex": 128,
"root": "0x0c499b373a1f0fe1b510a63563546d2d39e206895056a5af0143c5f30d639073"
},
"publicDataTree": {
Expand All @@ -58,8 +75,8 @@
}
}
},
"header": "0x0237797d6a2c04d20d4fa06b74482bd970ccd51a43d9b05b57e9b91fa1ae1cae000000010000000000000000000000000000000000000000000000000000000000000002001cedbd7ea5309ef9d1d159209835409bf41b6b1802597a52fa70cc82e934d900089a9d421a82c4a25f7acbebe69e638d5b064fa8a60e018793dcb0be53752c00f5a5fd42d16a20302798ef6ed309979b43003d2320d9f0e8ea9831a92759fb2e33ee2008411c04b99c24b313513d097a0d21a5040b6193d1f978b8226892d6000000101fd848aa69e1633722fe249a5b7f53b094f1c9cef9f5c694b073fd1cc5850dfb000000800c499b373a1f0fe1b510a63563546d2d39e206895056a5af0143c5f30d6390730000010023c08a6b1297210c5e24c76b9a936250a1ce2721576c26ea797c7ec35f9e46a9000000800000000000000000000000000000000000000000000000000000000000007a6900000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000674ae4902cf4a1c62581a88edae4234f887da6b9551ab1710339e43debc9c5093c6862f6dea7ff66fcd7f45c01f87dfa61f802d30530ea4e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c9bce2f1400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"publicInputsHash": "0x005838c184fb9da5be8d12382acd314219bbf72275c7242738bcb5c334f509ef",
"header": "0x0237797d6a2c04d20d4fa06b74482bd970ccd51a43d9b05b57e9b91fa1ae1cae000000010000000000000000000000000000000000000000000000000000000000000000001cedbd7ea5309ef9d1d159209835409bf41b6b1802597a52fa70cc82e934d900089a9d421a82c4a25f7acbebe69e638d5b064fa8a60e018793dcb0be53752c00000000000000000000000000000000000000000000000000000000000000002e33ee2008411c04b99c24b313513d097a0d21a5040b6193d1f978b8226892d6000000101fd848aa69e1633722fe249a5b7f53b094f1c9cef9f5c694b073fd1cc5850dfb000000000c499b373a1f0fe1b510a63563546d2d39e206895056a5af0143c5f30d6390730000008023c08a6b1297210c5e24c76b9a936250a1ce2721576c26ea797c7ec35f9e46a9000000800000000000000000000000000000000000000000000000000000000000007a6900000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000001b00000000000000000000000000000000000000000000000000000000677ecc0cb3402d01fb3d2005f49fa063cc2470cd3dcd8cee1e5f75a4eff0236113040956df38e3ec6b175c9a46e289972a69ffb812506b2100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c9bce0c3200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"publicInputsHash": "0x00275dc890b7255d4fa73d97e7ee5711f4bca05e6b8f8240b4c44468ff32f23e",
"blobInputs": "0x01010657f37554c781402a22917dee2f75def7ab966d7b770905398eba3c4440140ac4f3ee53aedc4865073ae7fb664e7401d10eadbe3bbcc266c35059f14826bb0000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"numTxs": 0
}
Expand Down
Loading
Loading