Skip to content

Commit

Permalink
feat: single tx block root rollup (#11096)
Browse files Browse the repository at this point in the history
- Remove `PrivateKernelEmpty` and `EmptyNested`.
- Introduce a new `SingleTxBlockRootRollup` circuit.
- Allow submitting a block without txs using `EmptyBlockRootRollup`.
  - Which allows updating the `l1_to_l2_message_tree`.
  • Loading branch information
LeilaWang authored Jan 9, 2025
1 parent 9d49393 commit bcc0168
Show file tree
Hide file tree
Showing 114 changed files with 3,024 additions and 2,664 deletions.
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());

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

0 comments on commit bcc0168

Please sign in to comment.