From 8f074bec2072f7151266e8fb43ad4fbadc2f9a77 Mon Sep 17 00:00:00 2001 From: Vladislav Volosnikov Date: Thu, 11 Sep 2025 08:14:00 -0500 Subject: [PATCH 1/9] Add addInteropRootsInBatch --- .../contracts/L2InteropRootStorage.sol | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/system-contracts/contracts/L2InteropRootStorage.sol b/system-contracts/contracts/L2InteropRootStorage.sol index 86add15925..c3df3ade08 100644 --- a/system-contracts/contracts/L2InteropRootStorage.sol +++ b/system-contracts/contracts/L2InteropRootStorage.sol @@ -9,6 +9,16 @@ error SidesLengthNotOne(); error InteropRootAlreadyExists(); error MessageRootIsZero(); +/// @param chainId The chain ID of the chain that the message root is for. +/// @param @param blockOrBatchNumber The block or batch number of the message root. Either of block number or batch number will be used, +/// depends on finality form of interop. +/// @param sides The message root sides. Note, that `sides` here are coming from `DynamicIncrementalMerkle` nomenclature. +struct InteropRoot { + uint256 chainId; + uint256 blockOrBatchNumber; + bytes32[] sides; +} + /** * @author Matter Labs * @custom:security-contact security@matterlabs.dev @@ -33,6 +43,25 @@ contract L2InteropRootStorage is SystemContractBase { uint256 blockOrBatchNumber, bytes32[] calldata sides ) external onlyCallFromBootloader { + _addInteropRoot(chainId, blockOrBatchNumber, sides); + } + + /// @dev Adds a group of interop roots to the L2InteropRootStorage contract. + /// @param interopRootsInput The array of interop roots. See the description above. + function addInteropRootsInBatch(InteropRoot[] calldata interopRootsInput) external onlyCallFromBootloader { + unchecked { + uint256 amountOfRoots = interopRootsInput.length; + for (uint256 i; i < amountOfRoots; ++i) { + _addInteropRoot( + interopRootsInput[i].chainId, + interopRootsInput[i].blockOrBatchNumber, + interopRootsInput[i].sides + ); + } + } + } + + function _addInteropRoot(uint256 chainId, uint256 blockOrBatchNumber, bytes32[] calldata sides) private { // In the current code sides should only contain the Interop Root itself, as mentioned above. if (sides.length != 1) { revert SidesLengthNotOne(); From accd7954a4ab6b2b1376feefbec07be012be444d Mon Sep 17 00:00:00 2001 From: Vladislav Volosnikov Date: Thu, 11 Sep 2025 08:15:56 -0500 Subject: [PATCH 2/9] Fix --- system-contracts/contracts/L2InteropRootStorage.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/system-contracts/contracts/L2InteropRootStorage.sol b/system-contracts/contracts/L2InteropRootStorage.sol index c3df3ade08..294aaf6854 100644 --- a/system-contracts/contracts/L2InteropRootStorage.sol +++ b/system-contracts/contracts/L2InteropRootStorage.sol @@ -10,7 +10,7 @@ error InteropRootAlreadyExists(); error MessageRootIsZero(); /// @param chainId The chain ID of the chain that the message root is for. -/// @param @param blockOrBatchNumber The block or batch number of the message root. Either of block number or batch number will be used, +/// @param blockOrBatchNumber The block or batch number of the message root. Either of block number or batch number will be used, /// depends on finality form of interop. /// @param sides The message root sides. Note, that `sides` here are coming from `DynamicIncrementalMerkle` nomenclature. struct InteropRoot { From e3a70c43fd68b03f80e1ed8e4844629f1bf304df Mon Sep 17 00:00:00 2001 From: Vladislav Volosnikov Date: Thu, 11 Sep 2025 08:47:10 -0500 Subject: [PATCH 3/9] Change addInteropRoot function --- .../contracts/L2InteropRootStorage.sol | 23 +++++++------------ 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/system-contracts/contracts/L2InteropRootStorage.sol b/system-contracts/contracts/L2InteropRootStorage.sol index 294aaf6854..2bc255d2bd 100644 --- a/system-contracts/contracts/L2InteropRootStorage.sol +++ b/system-contracts/contracts/L2InteropRootStorage.sol @@ -9,6 +9,11 @@ error SidesLengthNotOne(); error InteropRootAlreadyExists(); error MessageRootIsZero(); +/// @dev For both proof-based and commit-based interop, the `sides` parameter contains only the root. +/// @dev Once pre-commit interop is introduced, `sides` will include both the root and its associated sides. +/// @dev This interface is preserved now so that enabling pre-commit interop later requires no changes in interface. +/// @dev In proof-based and pre-commit interop, `blockOrBatchNumber` represents the block number, in commit-based interop, +/// it represents the batch number. This distinction reflects the implementation requirements of each interop finality form. /// @param chainId The chain ID of the chain that the message root is for. /// @param blockOrBatchNumber The block or batch number of the message root. Either of block number or batch number will be used, /// depends on finality form of interop. @@ -29,21 +34,9 @@ contract L2InteropRootStorage is SystemContractBase { mapping(uint256 chainId => mapping(uint256 blockOrBatchNumber => bytes32 interopRoot)) public interopRoots; /// @dev Adds a message root to the L2InteropRootStorage contract. - /// @dev For both proof-based and commit-based interop, the `sides` parameter contains only the root. - /// @dev Once pre-commit interop is introduced, `sides` will include both the root and its associated sides. - /// @dev This interface is preserved now so that enabling pre-commit interop later requires no changes in interface. - /// @dev In proof-based and pre-commit interop, `blockOrBatchNumber` represents the block number, in commit-based interop, - /// it represents the batch number. This distinction reflects the implementation requirements of each interop finality form. - /// @param chainId The chain ID of the chain that the message root is for. - /// @param blockOrBatchNumber The block or batch number of the message root. Either of block number or batch number will be used, - /// depends on finality form of interop, mentioned above. - /// @param sides The message root sides. Note, that `sides` here are coming from `DynamicIncrementalMerkle` nomenclature. - function addInteropRoot( - uint256 chainId, - uint256 blockOrBatchNumber, - bytes32[] calldata sides - ) external onlyCallFromBootloader { - _addInteropRoot(chainId, blockOrBatchNumber, sides); + /// @param interopRoot The interop roots. See the description of the corresponding struct. + function addInteropRoot(InteropRoot calldata interopRoot) external onlyCallFromBootloader { + _addInteropRoot(interopRoot.chainId, interopRoot.blockOrBatchNumber, interopRoot.sides); } /// @dev Adds a group of interop roots to the L2InteropRootStorage contract. From 3140242a86ae1c2191183adccd018e94c4e3610b Mon Sep 17 00:00:00 2001 From: Vladislav Volosnikov Date: Thu, 11 Sep 2025 08:53:18 -0500 Subject: [PATCH 4/9] Update system-contracts/contracts/L2InteropRootStorage.sol Co-authored-by: 0xValera <55665573+0xValera@users.noreply.github.com> --- system-contracts/contracts/L2InteropRootStorage.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/system-contracts/contracts/L2InteropRootStorage.sol b/system-contracts/contracts/L2InteropRootStorage.sol index 2bc255d2bd..83510b031b 100644 --- a/system-contracts/contracts/L2InteropRootStorage.sol +++ b/system-contracts/contracts/L2InteropRootStorage.sol @@ -34,7 +34,7 @@ contract L2InteropRootStorage is SystemContractBase { mapping(uint256 chainId => mapping(uint256 blockOrBatchNumber => bytes32 interopRoot)) public interopRoots; /// @dev Adds a message root to the L2InteropRootStorage contract. - /// @param interopRoot The interop roots. See the description of the corresponding struct. + /// @param interopRoot The interop root to be added. See the description of the corresponding struct. function addInteropRoot(InteropRoot calldata interopRoot) external onlyCallFromBootloader { _addInteropRoot(interopRoot.chainId, interopRoot.blockOrBatchNumber, interopRoot.sides); } From fa22dc933a468ba4e626ff98e816fa5f4463da14 Mon Sep 17 00:00:00 2001 From: Vladislav Volosnikov Date: Thu, 11 Sep 2025 08:53:26 -0500 Subject: [PATCH 5/9] Update system-contracts/contracts/L2InteropRootStorage.sol Co-authored-by: 0xValera <55665573+0xValera@users.noreply.github.com> --- system-contracts/contracts/L2InteropRootStorage.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/system-contracts/contracts/L2InteropRootStorage.sol b/system-contracts/contracts/L2InteropRootStorage.sol index 83510b031b..cc9852bcb6 100644 --- a/system-contracts/contracts/L2InteropRootStorage.sol +++ b/system-contracts/contracts/L2InteropRootStorage.sol @@ -40,7 +40,7 @@ contract L2InteropRootStorage is SystemContractBase { } /// @dev Adds a group of interop roots to the L2InteropRootStorage contract. - /// @param interopRootsInput The array of interop roots. See the description above. + /// @param interopRootsInput The array of interop roots to be added. See the description above. function addInteropRootsInBatch(InteropRoot[] calldata interopRootsInput) external onlyCallFromBootloader { unchecked { uint256 amountOfRoots = interopRootsInput.length; From 619584dbd39163d8ad51721821c088c666abf252 Mon Sep 17 00:00:00 2001 From: 0xValera <55665573+0xValera@users.noreply.github.com> Date: Thu, 11 Sep 2025 15:54:47 +0200 Subject: [PATCH 6/9] Update system-contracts/contracts/L2InteropRootStorage.sol --- system-contracts/contracts/L2InteropRootStorage.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/system-contracts/contracts/L2InteropRootStorage.sol b/system-contracts/contracts/L2InteropRootStorage.sol index cc9852bcb6..2672ab261f 100644 --- a/system-contracts/contracts/L2InteropRootStorage.sol +++ b/system-contracts/contracts/L2InteropRootStorage.sol @@ -34,7 +34,7 @@ contract L2InteropRootStorage is SystemContractBase { mapping(uint256 chainId => mapping(uint256 blockOrBatchNumber => bytes32 interopRoot)) public interopRoots; /// @dev Adds a message root to the L2InteropRootStorage contract. - /// @param interopRoot The interop root to be added. See the description of the corresponding struct. + /// @param interopRoot The interop root to be added. See the description of the corresponding struct above. function addInteropRoot(InteropRoot calldata interopRoot) external onlyCallFromBootloader { _addInteropRoot(interopRoot.chainId, interopRoot.blockOrBatchNumber, interopRoot.sides); } From 534c6f4441737da646eebc7accb5d20c41f3e01d Mon Sep 17 00:00:00 2001 From: 0xValera <55665573+0xValera@users.noreply.github.com> Date: Thu, 11 Sep 2025 15:55:04 +0200 Subject: [PATCH 7/9] Update system-contracts/contracts/L2InteropRootStorage.sol --- system-contracts/contracts/L2InteropRootStorage.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/system-contracts/contracts/L2InteropRootStorage.sol b/system-contracts/contracts/L2InteropRootStorage.sol index 2672ab261f..36f001a0a6 100644 --- a/system-contracts/contracts/L2InteropRootStorage.sol +++ b/system-contracts/contracts/L2InteropRootStorage.sol @@ -40,7 +40,7 @@ contract L2InteropRootStorage is SystemContractBase { } /// @dev Adds a group of interop roots to the L2InteropRootStorage contract. - /// @param interopRootsInput The array of interop roots to be added. See the description above. + /// @param interopRootsInput The array of interop roots to be added. See the description of the corresponding struct above. function addInteropRootsInBatch(InteropRoot[] calldata interopRootsInput) external onlyCallFromBootloader { unchecked { uint256 amountOfRoots = interopRootsInput.length; From c2c2dc8cc5edd4b7796685761d2b035c2250aaf5 Mon Sep 17 00:00:00 2001 From: Vladislav Volosnikov Date: Thu, 11 Sep 2025 09:16:16 -0500 Subject: [PATCH 8/9] Keep the old function for backward compatibility --- .../contracts/L2InteropRootStorage.sol | 21 ++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/system-contracts/contracts/L2InteropRootStorage.sol b/system-contracts/contracts/L2InteropRootStorage.sol index 36f001a0a6..4ecf6e2a1d 100644 --- a/system-contracts/contracts/L2InteropRootStorage.sol +++ b/system-contracts/contracts/L2InteropRootStorage.sol @@ -34,8 +34,27 @@ contract L2InteropRootStorage is SystemContractBase { mapping(uint256 chainId => mapping(uint256 blockOrBatchNumber => bytes32 interopRoot)) public interopRoots; /// @dev Adds a message root to the L2InteropRootStorage contract. + /// @dev For both proof-based and commit-based interop, the `sides` parameter contains only the root. + /// @dev Once pre-commit interop is introduced, `sides` will include both the root and its associated sides. + /// @dev This interface is preserved now so that enabling pre-commit interop later requires no changes in interface. + /// @dev In proof-based and pre-commit interop, `blockOrBatchNumber` represents the block number, in commit-based interop, + /// it represents the batch number. This distinction reflects the implementation requirements of each interop finality form. + /// @param chainId The chain ID of the chain that the message root is for. + /// @param blockOrBatchNumber The block or batch number of the message root. Either of block number or batch number will be used, + /// depends on finality form of interop, mentioned above. + /// @param sides The message root sides. Note, that `sides` here are coming from `DynamicIncrementalMerkle` nomenclature. + function addInteropRoot( + uint256 chainId, + uint256 blockOrBatchNumber, + bytes32[] calldata sides + ) external onlyCallFromBootloader { + _addInteropRoot(chainId, blockOrBatchNumber, sides); + } + + /// @dev Adds a message root to the L2InteropRootStorage contract. + /// @dev Currently duplicates `addInteropRoot` for backward compatibility. /// @param interopRoot The interop root to be added. See the description of the corresponding struct above. - function addInteropRoot(InteropRoot calldata interopRoot) external onlyCallFromBootloader { + function addSingleInteropRoot(InteropRoot calldata interopRoot) external onlyCallFromBootloader { _addInteropRoot(interopRoot.chainId, interopRoot.blockOrBatchNumber, interopRoot.sides); } From 010844292ad56b336cfbcebdc775d7e2ca1fb6f5 Mon Sep 17 00:00:00 2001 From: Vladislav Volosnikov Date: Thu, 11 Sep 2025 09:40:05 -0500 Subject: [PATCH 9/9] Add a comment about the next version --- system-contracts/contracts/L2InteropRootStorage.sol | 1 + 1 file changed, 1 insertion(+) diff --git a/system-contracts/contracts/L2InteropRootStorage.sol b/system-contracts/contracts/L2InteropRootStorage.sol index 4ecf6e2a1d..3104c99363 100644 --- a/system-contracts/contracts/L2InteropRootStorage.sol +++ b/system-contracts/contracts/L2InteropRootStorage.sol @@ -39,6 +39,7 @@ contract L2InteropRootStorage is SystemContractBase { /// @dev This interface is preserved now so that enabling pre-commit interop later requires no changes in interface. /// @dev In proof-based and pre-commit interop, `blockOrBatchNumber` represents the block number, in commit-based interop, /// it represents the batch number. This distinction reflects the implementation requirements of each interop finality form. + /// @dev Note: should be removed in the next protocol version. /// @param chainId The chain ID of the chain that the message root is for. /// @param blockOrBatchNumber The block or batch number of the message root. Either of block number or batch number will be used, /// depends on finality form of interop, mentioned above.