-
Notifications
You must be signed in to change notification settings - Fork 614
feat: wonky rollups #7189
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: wonky rollups #7189
Changes from 7 commits
0e9c978
3018092
dde3369
5600ab5
c540065
f4a5dd6
80f34c1
7fd688a
e5fb78d
6156621
517e7b0
2fac93d
178a9ec
70ce2e2
ca7accd
dc41c79
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -6,6 +6,7 @@ pragma solidity >=0.8.18; | |
| import {Errors} from "../Errors.sol"; | ||
| import {Constants} from "../ConstantsGen.sol"; | ||
| import {Hash} from "../Hash.sol"; | ||
| import {MerkleLib} from "../MerkleLib.sol"; | ||
|
|
||
| /** | ||
| * @title Txs Decoder Library | ||
|
|
@@ -261,7 +262,7 @@ library TxsDecoder { | |
| } | ||
| } | ||
|
|
||
| return computeRoot(vars.baseLeaves); | ||
| return computeUnbalancedRoot(vars.baseLeaves); | ||
| } | ||
|
|
||
| /** | ||
|
|
@@ -516,6 +517,36 @@ library TxsDecoder { | |
| return _leafs[0]; | ||
| } | ||
|
|
||
| /** | ||
| * @notice Computes the root for a binary unbalanced Merkle-tree given the leaves and subtree sizes. | ||
| * @dev Filled in greedily with subtrees. Useful for txsEffectHash and outHash tree. | ||
| * @param _leaves - The 32 bytes leafs to build the tree of. | ||
| * @return The root of the Merkle tree. | ||
| */ | ||
| function computeUnbalancedRoot(bytes32[] memory _leaves) internal pure returns (bytes32) { | ||
| // e.g. an unbalanced tree of 7 txs will contain subtrees of 4, 2, and 1 tx(s) | ||
| // Encoded as 000400020001 | ||
| bytes memory subtreeSizes = MerkleLib.computeSubtreeSizes(_leaves.length); | ||
| // We collect the roots of each subtree | ||
| bytes32 root; | ||
| uint256 currentSubtreeSize; | ||
| uint256 processedLeaves = 0; | ||
| // We must calculate the smaller rightmost subtrees first, hence working backwards through the leaves/sizes arr | ||
| for (uint256 j = subtreeSizes.length; j > 0; j -= 2) { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Looks like the subtreeSizes are simply the non-zero bits of the binary form of numTxs. (☝️ Might contain bug and incorrect syntax)
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh of course!! Thanks, great catch. Will also remove the subtree size fn and refactor min/max path length (the latter will disappear once we move to a balanced out_hash tree, so I won't spend too much time on it) |
||
| currentSubtreeSize = uint16(bytes2(bytes.concat(subtreeSizes[j - 2], subtreeSizes[j - 1]))); | ||
| uint256 start = _leaves.length - processedLeaves - currentSubtreeSize; | ||
| bytes32[] memory leavesInSubtree = new bytes32[](currentSubtreeSize); | ||
| for (uint256 i = start; i < start + currentSubtreeSize; i++) { | ||
| leavesInSubtree[i - start] = _leaves[i]; | ||
| } | ||
| bytes32 subtreeRoot = computeRoot(leavesInSubtree); | ||
| root = | ||
| j == subtreeSizes.length ? subtreeRoot : Hash.sha256ToField(bytes.concat(subtreeRoot, root)); | ||
| processedLeaves += currentSubtreeSize; | ||
| } | ||
| return root; | ||
| } | ||
|
|
||
| /** | ||
| * @notice Wrapper around the slicing to avoid some stack too deep | ||
| * @param _data - The data to slice | ||
|
|
@@ -592,18 +623,6 @@ library TxsDecoder { | |
| } else if (_numTxEffects == 1) { | ||
| return 1; | ||
| } | ||
|
|
||
| uint32 v = _numTxEffects; | ||
|
|
||
| // the following rounds _numTxEffects up to the next power of 2 (works only for 4 bytes value!) | ||
| v--; | ||
| v |= v >> 1; | ||
| v |= v >> 2; | ||
| v |= v >> 4; | ||
| v |= v >> 8; | ||
| v |= v >> 16; | ||
| v++; | ||
|
|
||
| return v - _numTxEffects; | ||
| return 0; | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -23,6 +23,7 @@ contract Outbox is IOutbox { | |
| // This is the outhash specified by header.globalvariables.outHash of any given block. | ||
| bytes32 root; | ||
| uint256 minHeight; | ||
| uint256 maxHeight; | ||
| mapping(uint256 => bool) nullified; | ||
| } | ||
|
|
||
|
|
@@ -41,8 +42,9 @@ contract Outbox is IOutbox { | |
| * @param _l2BlockNumber - The L2 Block Number in which the L2 to L1 messages reside | ||
| * @param _root - The merkle root of the tree where all the L2 to L1 messages are leaves | ||
| * @param _minHeight - The min height of the merkle tree that the root corresponds to | ||
| * @param _maxHeight - The max height of the merkle tree that the root corresponds to | ||
| */ | ||
| function insert(uint256 _l2BlockNumber, bytes32 _root, uint256 _minHeight) | ||
| function insert(uint256 _l2BlockNumber, bytes32 _root, uint256 _minHeight, uint256 _maxHeight) | ||
| external | ||
| override(IOutbox) | ||
| { | ||
|
|
@@ -60,8 +62,9 @@ contract Outbox is IOutbox { | |
|
|
||
| roots[_l2BlockNumber].root = _root; | ||
| roots[_l2BlockNumber].minHeight = _minHeight; | ||
| roots[_l2BlockNumber].maxHeight = _maxHeight; | ||
|
|
||
| emit RootAdded(_l2BlockNumber, _root, _minHeight); | ||
| emit RootAdded(_l2BlockNumber, _root, _minHeight, _maxHeight); | ||
| } | ||
|
|
||
| /** | ||
|
|
@@ -103,16 +106,15 @@ contract Outbox is IOutbox { | |
|
|
||
| // Min height = height of rollup layers | ||
| // The smallest num of messages will require a subtree of height 1 | ||
| uint256 treeHeight = rootData.minHeight; | ||
| if (treeHeight > _path.length) { | ||
| revert Errors.Outbox__InvalidPathLength(treeHeight, _path.length); | ||
| uint256 minHeight = rootData.minHeight; | ||
| if (minHeight > _path.length) { | ||
| revert Errors.Outbox__InvalidPathLength(minHeight, _path.length); | ||
| } | ||
|
|
||
| // Max height = height of rollup layers + max possible subtree height | ||
| // The max num of messages N will require a subtree of height log2(N) | ||
| uint256 maxSubtreeHeight = calculateTreeHeightFromSize(Constants.MAX_NEW_L2_TO_L1_MSGS_PER_TX); | ||
| if (treeHeight + maxSubtreeHeight < _path.length) { | ||
| revert Errors.Outbox__InvalidPathLength(treeHeight + maxSubtreeHeight, _path.length); | ||
| // Max height = max height of rollup layers + max possible subtree height | ||
| uint256 maxHeight = rootData.maxHeight; | ||
| if (maxHeight < _path.length) { | ||
| revert Errors.Outbox__InvalidPathLength(maxHeight, _path.length); | ||
| } | ||
|
|
||
| bytes32 messageHash = _message.sha256ToField(); | ||
|
|
@@ -138,22 +140,4 @@ contract Outbox is IOutbox { | |
| { | ||
| return roots[_l2BlockNumber].nullified[_leafIndex]; | ||
| } | ||
|
|
||
| /** | ||
| * @notice Calculates a tree height from the amount of elements in the tree | ||
| * @dev - This mirrors the function in TestUtil, but assumes _size is an exact power of 2 | ||
| * @param _size - The number of elements in the tree | ||
| */ | ||
| function calculateTreeHeightFromSize(uint256 _size) internal pure returns (uint256) { | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Moved to |
||
| /// We need the height of the tree that will contain all of our leaves, | ||
| /// hence the next highest power of two from the amount of leaves - Math.ceil(Math.log2(x)) | ||
| uint256 height = 0; | ||
|
|
||
| /// While size > 1, we divide by two, and count how many times we do this; producing a rudimentary way of calculating Math.Floor(Math.log2(x)) | ||
| while (_size > 1) { | ||
| _size >>= 1; | ||
| height++; | ||
| } | ||
| return height; | ||
| } | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.